@@ -104,6 +104,11 @@ void ExtrudeLayers (
104104 bool allowForTetsAndPyras,
105105 const ANumber* aRelZOut)
106106{
107+ if (allowForTetsAndPyras){
108+ ExtrudeLayersMixed (grid, layers, aaPos, sh, aRelZOut);
109+ return ;
110+ }
111+
107112 UG_COND_THROW (layers.size () < 2 , " At least 2 layers are required to perform extrusion!" );
108113
109114 grid.begin_marking ();
@@ -450,6 +455,208 @@ void ExtrudeLayers (
450455}
451456
452457
458+ void ExtrudeLayersMixed (
459+ Grid& grid,
460+ const RasterLayers& layers,
461+ Grid::VertexAttachmentAccessor<AVector3> aaPos,
462+ ISubsetHandler& sh,
463+ const ANumber* aRelZOut)
464+ {
465+ UG_COND_THROW (layers.size () < 2 , " At least 2 layers are required to perform extrusion!" );
466+
467+ vector<Vertex*> curVrts; // list of vertices that are considered for extrusion
468+ vector<Vertex*> nextVrts; // used to determine the set of vertices that can be extruded
469+ vector<Face*> curFaces; // list of faces that are considered for extrusion
470+ vector<Face*> nextFaces; // used to determine the set of faces that can be extruded
471+
472+ grid.reserve <Vertex>(grid.num_vertices () * layers.size ());
473+ grid.reserve <Volume>(grid.num_faces () * layers.size () - 1 );
474+
475+ AInt aVrtInd;
476+ grid.attach_to_vertices (aVrtInd);
477+ Grid::VertexAttachmentAccessor<AInt> aaVrtInd (grid, aVrtInd);
478+
479+ Grid::VertexAttachmentAccessor<ANumber> aaRelZOut;
480+ if (aRelZOut){
481+ ANumber aRelZ = *aRelZOut;
482+ if (!grid.has_vertex_attachment (aRelZ))
483+ grid.attach_to_vertices (aRelZ);
484+ aaRelZOut.access (grid, aRelZ);
485+ }
486+
487+ // we have to determine the vertices that can be projected onto the top of the
488+ // given layers-stack. Only those will be used during extrusion
489+ // all considered vertices will be marked.
490+ const RasterLayers::layer_t & top = layers.top ();
491+ const int topLayerInd = (int )layers.num_layers () - 1 ;
492+ for (VertexIterator i = grid.begin <Vertex>(); i != grid.end <Vertex>(); ++i){
493+ Vertex* v = *i;
494+ vector2 c (aaPos[v].x (), aaPos[v].y ());
495+ // number val = layers.relative_to_global_height(c, topLayerInd);
496+ number val = layers.heightfield (topLayerInd).interpolate (c, 1 );
497+ if (val != top.heightfield .no_data_value ()){
498+ aaPos[v].z () = val;
499+ aaVrtInd[v] = (int )curVrts.size ();
500+ curVrts.push_back (v);
501+ sh.assign_subset (v, topLayerInd);
502+ }
503+ else
504+ aaVrtInd[v] = -1 ;
505+ }
506+
507+ if (curVrts.size () < 3 ){
508+ UG_LOG (" Not enough vertices lie in the region of the surface layer\n " );
509+ return ;
510+ }
511+
512+ if (aaRelZOut.valid ()){
513+ for (size_t ivrt = 0 ; ivrt < curVrts.size (); ++ivrt)
514+ aaRelZOut[curVrts[ivrt]] = topLayerInd;
515+ }
516+
517+ // make sure that only triangles are used
518+ if (grid.num <Quadrilateral>() > 0 ){
519+ UG_LOG (" WARNING: Converting all quadrilaterals to triangles\n " );
520+ Triangulate (grid, grid.begin <Quadrilateral>(), grid.end <Quadrilateral>(), &aaPos);
521+ }
522+
523+ // all faces of the initial triangulation that are only connected to marked
524+ // vertices are considered for extrusion
525+ for (FaceIterator fi = grid.begin <Face>(); fi != grid.end <Face>(); ++fi){
526+ Face* f = *fi;
527+ bool allConsidered = true ;
528+ Face::ConstVertexArray vrts = f->vertices ();
529+ const size_t numVrts = f->num_vertices ();
530+ for (size_t i = 0 ; i < numVrts; ++i){
531+ if (aaVrtInd[vrts[i]] == -1 ){
532+ allConsidered = false ;
533+ break ;
534+ }
535+ }
536+ if (allConsidered)
537+ curFaces.push_back (f);
538+ }
539+
540+ if (curFaces.empty ()){
541+ UG_LOG (" Not enough faces lie in the region of the surface layer\n " );
542+ return ;
543+ }
544+
545+
546+ nextVrts.reserve (curVrts.size ());
547+ nextFaces.reserve (curFaces.size ());
548+
549+
550+ for (int ilayer = (int )layers.size () - 2 ; ilayer > 0 ; --ilayer){
551+
552+ nextVrts.clear ();
553+ nextFaces.clear ();
554+
555+ const int nextLayer = ilayer - 1 ;
556+
557+ // trace rays from the current vertices down through the layers until the
558+ // next valid entry is found. If none is found, the vertex will either be ignored
559+ // from then on (allowForTetsAndPyras == false) or a dummy vertex will be inserted.
560+ for (size_t icur = 0 ; icur < curVrts.size (); ++icur){
561+ Vertex* v = curVrts[icur];
562+ vector2 c (aaPos[v].x (), aaPos[v].y ());
563+ number curH = aaPos[v].z ();
564+ // number nextH = layers.relative_to_global_height(c, (number) nextLayer);
565+ number nextH = layers.heightfield (nextLayer).interpolate (c, 1 );
566+ if (curH - nextH < layers.min_height (nextLayer)){
567+ nextVrts.push_back (v);
568+ }
569+ else {
570+ Vertex* nextVrt = *grid.create <RegularVertex>(v);
571+ aaVrtInd[nextVrt] = aaVrtInd[v];
572+ aaPos[nextVrt] = aaPos[v];
573+ aaPos[nextVrt].z () = nextH;
574+ sh.assign_subset (nextVrt, nextLayer);
575+ nextVrts.push_back (nextVrt);
576+
577+ if (aaRelZOut.valid ()){
578+ aaRelZOut[nextVrt] = nextLayer;
579+ }
580+ }
581+ }
582+
583+ // now find the faces which connect those vertices
584+ for (size_t iface = 0 ; iface < curFaces.size (); ++iface){
585+ Face* f = curFaces[iface];
586+ Face::ConstVertexArray vrts = f->vertices ();
587+ int numNew = 0 ;
588+ int firstSame = -1 ;
589+ int firstNew = -1 ;
590+ TriangleDescriptor nextTriDesc;
591+ for (int i = 0 ; i < 3 ; ++i){
592+ int vrtInd = aaVrtInd[vrts[i]];
593+ nextTriDesc.set_vertex (i, nextVrts[vrtInd]);
594+ if (nextVrts[vrtInd] == curVrts[vrtInd]){
595+ if (firstSame == -1 )
596+ firstSame = i;
597+ }
598+ else {
599+ ++numNew;
600+ if (firstNew == -1 )
601+ firstNew = i;
602+ }
603+ }
604+
605+ Face* nextFace = f;
606+ if (numNew > 0 ){
607+ nextFace = *grid.create <Triangle>(nextTriDesc, f);
608+ sh.assign_subset (nextFace, nextLayer);
609+ }
610+ nextFaces.push_back (nextFace);
611+
612+ Volume* newVol = NULL ;
613+
614+ switch (numNew){
615+ case 0 :// no new volume to be built.
616+ break ;
617+ case 1 : {// build a tetrahedron
618+ TetrahedronDescriptor tetDesc (nextTriDesc.vertex (0 ),
619+ nextTriDesc.vertex (1 ),
620+ nextTriDesc.vertex (2 ),
621+ vrts[firstNew]);
622+ newVol = *grid.create <Tetrahedron>(tetDesc);
623+ } break ;
624+
625+ case 2 : {// build a pyramid
626+ int i0 = (firstSame + 1 ) % 3 ;
627+ int i1 = (firstSame + 2 ) % 3 ;
628+ PyramidDescriptor pyrDesc (nextTriDesc.vertex (i0),
629+ nextTriDesc.vertex (i1),
630+ vrts[i1],
631+ vrts[i0],
632+ vrts[firstSame]);
633+ newVol = *grid.create <Pyramid>(pyrDesc);
634+ } break ;
635+
636+ case 3 : {// build a prism
637+ PrismDescriptor prismDesc (nextTriDesc.vertex (0 ),
638+ nextTriDesc.vertex (1 ),
639+ nextTriDesc.vertex (2 ),
640+ vrts[0 ],
641+ vrts[1 ],
642+ vrts[2 ]);
643+ newVol = *grid.create <Prism>(prismDesc);
644+ } break ;
645+ }
646+
647+ if (newVol)
648+ sh.assign_subset (newVol, nextLayer);
649+ }
650+
651+ // swap containers and perform extrusion
652+ curVrts.swap (nextVrts);
653+ curFaces.swap (nextFaces);
654+ }
655+
656+ // clean up
657+ grid.detach_from_vertices (aVrtInd);
658+ }
659+
453660// / projects the given (surface-) grid to the specified raster
454661void ProjectToLayer (
455662 Grid& grid,
0 commit comments