// The function that tests whether a surface is a QuadToTri top surface and whether // there are conflicts. If surface is not a top for a valid QuadToTri region or if // there are QuadToTri conflicts, return 0. // if the surface turns out to be the source of a toroidal loop extrusion (which will then // NOT have geo.Mode == COPIED_ENTITY), return 2 (this will require special meshing considerations). // Note that RemoveDuplicateSurfaces() makes this DIFFICULT. // Also, the type of QuadToTri interface is placed into the // pointer argument quadToTri. . // Added 2010-12-09. int IsValidQuadToTriTop(GFace *face, int *quadToTri, bool *detectQuadToTriTop) { (*quadToTri) = NO_QUADTRI; (*detectQuadToTriTop) = false; int is_toroidal_quadtri = 0; GModel *model = face->model(); // First thing is first: determine if this is a toroidal quadtri extrusion. if so, can skip the rest // It seems the member pointers to neighboring regions for extruded top faces are not set. // For now, have to loop through // ALL the regions to see if the presently considered face belongs to the region. // The following loop will find all the regions that the face bounds, and determine // whether the face is a top face of the region (including whether the region is even extruded). // After that information is determined, function can test for QuadToTri neighbor conflicts. // first determine if this is toroidal quadtotri is_toroidal_quadtri = IsInToroidalQuadToTri(face); if( is_toroidal_quadtri ) (*detectQuadToTriTop) = true; else{ std::vector<GRegion *> top_regions; std::vector<GRegion *> adjacent_regions; std::vector<GRegion *> all_regions; int numRegions = 0; int numTopRegions = 0; std::set<GRegion *, GEntityLessThan>::iterator itreg; for( itreg = model->firstRegion(); itreg != model->lastRegion(); itreg++ ) all_regions.push_back( (*itreg) ); for(unsigned int i_reg = 0; i_reg < all_regions.size(); i_reg++ ){ // save time if( numRegions >= 2 ) break; GRegion *region = all_regions[i_reg]; // is region in the current model's regions or is it deleted? if( !FindVolume( ( region->tag() ) ) ) continue; // does face belong to region? std::list<GFace *> region_faces = std::list<GFace *>( region->faces() ); if( std::find( region_faces.begin(), region_faces.end(), face ) != region_faces.end() ){ adjacent_regions.push_back(region); numRegions++; } else continue; // is region a structured extruded? if( !(region->meshAttributes.extrude && region->meshAttributes.extrude->mesh.ExtrudeMesh && region->meshAttributes.extrude->geo.Mode == EXTRUDED_ENTITY) ) continue; // Test whether the face is a top for the region if( IsSurfaceATopForRegion(region, face) ){ top_regions.push_back(region); numTopRegions++; if( region->meshAttributes.extrude->mesh.QuadToTri ) (*detectQuadToTriTop) = true; } } // MAIN test of whether this is even a quadToTri extrusion lateral // the only return 0 path that is NOT an error if( !(*detectQuadToTriTop) ) return 0; ExtrudeParams *ep = face->meshAttributes.extrude; if(!ep && !is_toroidal_quadtri){ Msg::Error("In IsValidQuadToTriTop(), no extrude info for surface %d.", face->tag() ); return 0; } if( ep->geo.Mode != COPIED_ENTITY ){ Msg::Error("In IsValidQuadToTriTop(), surface %d is not copied from source.", face->tag() ); return 0; } if( ep->mesh.QuadToTri == 0){ Msg::Error("In IsValidQuadToTriTop(), surface %d was determined to be the top surface " "for a QuadToTri extrusion, but does not have QuadToTri parameters set within itself.", face->tag() ); return 0; } GFace *face_source = model->getFaceByTag(std::abs(ep->geo.Source)); if(!face_source){ Msg::Error("In IsValidQuadToTriTop(), unknown source face number %d.", face->meshAttributes.extrude->geo.Source); return 0; } if(numRegions > 2){ Msg::Error("In IsValidQuadToTriTop(), too many regions adjacent to surface %d.", face->tag() ); return 0; } if( top_regions.size() ){ (*quadToTri) = top_regions[0]->meshAttributes.extrude->mesh.QuadToTri; } // Make sure that face is the top for only one region. if not, then there will likely // be conflicts (two regions extruded into each other). if( top_regions.size() > 1 ){ Msg::Error("In IsValidQuadToTriTop(), QuadToTri top surface %d identified as top " "surface for more than one region. Likely conflict.", face->tag() ); return 0; } } // end of else that executes if NOT toroidal extrusion // this is technically redundant...but if changes are made, it's good to keep this here at the end for safety if( !(*detectQuadToTriTop) ) return 0; if( !is_toroidal_quadtri ) return 1; else if( is_toroidal_quadtri == 1 ) { return 2;} // for toroidal extrusion else return 3; }
int SubdivideExtrudedMesh(GModel *m) { // get all non-recombined extruded regions and vertices; also, // create a vector of quadToTri regions that have NOT been meshed // yet std::vector<GRegion*> regions, regions_quadToTri; MVertexRTree pos(CTX::instance()->geom.tolerance * CTX::instance()->lc); for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); it++){ ExtrudeParams *ep = (*it)->meshAttributes.extrude; if(ep && ep->mesh.ExtrudeMesh && ep->geo.Mode == EXTRUDED_ENTITY && !ep->mesh.Recombine){ regions.push_back(*it); insertAllVertices(*it, pos); } // create vector of valid quadToTri regions...not all will necessarily be meshed here. if(ep && ep->mesh.ExtrudeMesh && ep->geo.Mode == EXTRUDED_ENTITY && ep->mesh.Recombine && ep->mesh.QuadToTri){ regions_quadToTri.push_back(*it); } } if(regions.empty()) return 0; Msg::Info("Subdividing extruded mesh"); // create edges on lateral sides of "prisms" std::set<std::pair<MVertex*, MVertex*> > edges; for(unsigned int i = 0; i < regions.size(); i++) phase1(regions[i], pos, edges); // swap lateral edges to make them "tet-compatible" int j = 0, swap; std::set<std::pair<MVertex*, MVertex*> > edges_swap; do { swap = 0; for(unsigned int i = 0; i < regions.size(); i++) phase2(regions[i], pos, edges, edges_swap, swap); Msg::Info("Swapping %d", swap); if(j && j == swap) { Msg::Error("Unable to subdivide extruded mesh: change surface mesh or"); Msg::Error("recombine extrusion instead"); return -1; } j = swap; } while(swap); // delete volume elements and create tetrahedra instead for(unsigned int i = 0; i < regions.size(); i++){ GRegion *gr = regions[i]; for(unsigned int i = 0; i < gr->tetrahedra.size(); i++) delete gr->tetrahedra[i]; gr->tetrahedra.clear(); for(unsigned int i = 0; i < gr->hexahedra.size(); i++) delete gr->hexahedra[i]; gr->hexahedra.clear(); for(unsigned int i = 0; i < gr->prisms.size(); i++) delete gr->prisms[i]; gr->prisms.clear(); for(unsigned int i = 0; i < gr->pyramids.size(); i++) delete gr->pyramids[i]; gr->pyramids.clear(); phase3(gr, pos, edges); // re-Extrude bounding surfaces using edges as constraint std::list<GFace*> faces = gr->faces(); for(std::list<GFace*>::iterator it = faces.begin(); it != faces.end(); it++){ ExtrudeParams *ep = (*it)->meshAttributes.extrude; if(ep && ep->mesh.ExtrudeMesh && ep->geo.Mode == EXTRUDED_ENTITY && !ep->mesh.Recombine){ GFace *gf = *it; Msg::Info("Remeshing surface %d", gf->tag()); for(unsigned int i = 0; i < gf->triangles.size(); i++) delete gf->triangles[i]; gf->triangles.clear(); for(unsigned int i = 0; i < gf->quadrangles.size(); i++) delete gf->quadrangles[i]; gf->quadrangles.clear(); MeshExtrudedSurface(gf, &edges); } } } // now mesh the QuadToTri regions. Everything can be done locally // for each quadToTri region, but still use edge set from above just // to make sure laterals get remeshed properly ( // QuadToTriEdgeGenerator detects if the neighbor has been meshed or // if a lateral surface should remain static for any other reason). // If this function detects allNonGlobalSharedLaterals, it won't // mesh the region (should already be done in ExtrudeMesh). for(unsigned int i = 0; i < regions_quadToTri.size(); i++){ GRegion *gr = regions_quadToTri[i]; MVertexRTree pos_local(CTX::instance()->geom.tolerance * CTX::instance()->lc); insertAllVertices(gr, pos_local); meshQuadToTriRegionAfterGlobalSubdivide(gr, &edges, pos_local); } // carve holes if any // TODO: update extrusion information for(unsigned int i = 0; i < regions.size(); i++){ GRegion *gr = regions[i]; ExtrudeParams *ep = gr->meshAttributes.extrude; if(ep->mesh.Holes.size()){ std::map<int, std::pair<double, std::vector<int> > >::iterator it; for(it = ep->mesh.Holes.begin(); it != ep->mesh.Holes.end(); it++) carveHole(gr, it->first, it->second.first, it->second.second); } } for(unsigned int i = 0; i < regions_quadToTri.size(); i++){ GRegion *gr = regions_quadToTri[i]; ExtrudeParams *ep = gr->meshAttributes.extrude; if(ep->mesh.Holes.size()){ std::map<int, std::pair<double, std::vector<int> > >::iterator it; for(it = ep->mesh.Holes.begin(); it != ep->mesh.Holes.end(); it++) carveHole(gr, it->first, it->second.first, it->second.second); } } return 1; }