Skip to content

Commit 4d661dc

Browse files
committed
Implemented ExtrudeLayersMixed, which is should create layers with
mixed element types and assign subsets in a more consistent manner. Still work in progress
1 parent 4584547 commit 4d661dc

File tree

3 files changed

+234
-0
lines changed

3 files changed

+234
-0
lines changed

ugbase/lib_grid/algorithms/grid_generation/horizontal_layers_mesher.cpp

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
454661
void ProjectToLayer(
455662
Grid& grid,

ugbase/lib_grid/algorithms/grid_generation/horizontal_layers_mesher.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,30 @@ void ExtrudeLayers(
8282
bool allowForTetsAndPyras,
8383
const ANumber* aRelZOut = NULL);
8484

85+
86+
/** grid has to contain a triangluation of the surface grid of raster-layers.
87+
* Only x- and y- coordinates of the vertices of the reference triangulation are
88+
* considered, since all vertices are projected to their respective layers.
89+
* The resulting mesh will contain prisms, pyramids, and tetrahedra
90+
*
91+
* \param grid The grid whose surface triangulation will be extended to
92+
* a volume mesh.
93+
* \param layers A stack of rasters, defining the layered domain.
94+
* \param aaPos vertex positions
95+
* \param sh Element subsets will be assigned depending on the index of the
96+
* layer in which an element is located.
97+
* \param aRelZOut (optional) Vertex attachment to which the relative height of
98+
* each vertex will be written. This value will equal the layer
99+
* index for which a specific vertex has been created.
100+
*/
101+
void ExtrudeLayersMixed (
102+
Grid& grid,
103+
const RasterLayers& layers,
104+
Grid::VertexAttachmentAccessor<AVector3> aaPos,
105+
ISubsetHandler& sh,
106+
const ANumber* aRelZOut);
107+
108+
85109
/// projects the given (surface-) grid to the specified raster
86110
void ProjectToLayer(
87111
Grid& grid,

ugbase/lib_grid/algorithms/raster_layer_util.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,9 @@ relative_to_global_height_simple(const vector2& c, number relHeight) const
384384
UG_COND_THROW(upper.first < 0, "Invalid upper layer for coordinate " << c
385385
<< " and relative height " << relHeight);
386386

387+
if(upper.second < lower.second)
388+
return upper.second;
389+
387390
number layerDiff = max(1, upper.first - lower.first);
388391
number rel = (clip<number>(relHeight - (number)relHeightLower, 0, 1)
389392
+ relHeightLower - lower.first)

0 commit comments

Comments
 (0)