// build the BDS from a list of GFace // This is a TRUE copy BDS_Mesh *gmsh2BDS(std::list<GFace*> &l) { BDS_Mesh *m = new BDS_Mesh; for (std::list<GFace*>::iterator it = l.begin(); it != l.end(); ++it){ GFace *gf = *it; m->add_geom(gf->tag(), 2); BDS_GeomEntity *g2 = m->get_geom(gf->tag(), 2); for (unsigned int i = 0; i < gf->triangles.size(); i++){ MTriangle *e = gf->triangles[i]; BDS_Point *p[3]; for (int j = 0; j < 3; j++){ p[j] = m->find_point(e->getVertex(j)->getNum()); if (!p[j]) { p[j] = m->add_point(e->getVertex(j)->getNum(), e->getVertex(j)->x(), e->getVertex(j)->y(), e->getVertex(j)->z()); SPoint2 param; reparamMeshVertexOnFace(e->getVertex(j), gf, param); p[j]->u = param[0]; p[j]->v = param[1]; m->add_geom(e->getVertex(j)->onWhat()->tag(), e->getVertex(j)->onWhat()->dim()); BDS_GeomEntity *g = m->get_geom(e->getVertex(j)->onWhat()->tag(), e->getVertex(j)->onWhat()->dim()); p[j]->g = g; } } BDS_Face *f = m->add_triangle(p[0]->iD, p[1]->iD, p[2]->iD); f->g = g2; } } return m; }
void Centerline::createSplitCompounds() { //number of discrete vertices, edges, faces and regions for the mesh NV = current->getMaxElementaryNumber(0); NE = current->getMaxElementaryNumber(1); NF = current->getMaxElementaryNumber(2); NR = current->getMaxElementaryNumber(3); // Remesh new faces (Compound Lines and Compound Surfaces) Msg::Info("Centerline: creating split compounds ..."); //Parametrize Compound Lines for (int i=0; i < NE; i++){ std::vector<GEdge*>e_compound; GEdge *pe = current->getEdgeByTag(i+1);//current edge e_compound.push_back(pe); int num_gec = NE+i+1; Msg::Info("Create Compound Line (%d) = %d discrete edge", num_gec, pe->tag()); GEdge *gec = current->addCompoundEdge(e_compound,num_gec); if (CTX::instance()->mesh.algo2d != ALGO_2D_BAMG){ gec->meshAttributes.method = MESH_TRANSFINITE; gec->meshAttributes.nbPointsTransfinite = nbPoints+1; gec->meshAttributes.typeTransfinite = 0; gec->meshAttributes.coeffTransfinite = 1.0; } } // Parametrize Compound surfaces std::list<GEdge*> U0; for (int i=0; i < NF; i++){ std::vector<GFace*> f_compound; GFace *pf = current->getFaceByTag(i+1);//current face f_compound.push_back(pf); int num_gfc = NF+i+1; Msg::Info("Create Compound Surface (%d) = %d discrete face", num_gfc, pf->tag()); //1=conf_spectral 4=convex_circle, 7=conf_fe GFace *gfc = current->addCompoundFace(f_compound, 7, 0, num_gfc); gfc->meshAttributes.recombine = recombine; gfc->addPhysicalEntity(1); current->setPhysicalName("wall", 2, 1);//tag 1 } }
int GModel::writeDIFF(const std::string &name, bool binary, bool saveAll, double scalingFactor) { if(binary){ Msg::Error("Binary DIFF output is not implemented"); return 0; } FILE *fp = Fopen(name.c_str(), binary ? "wb" : "w"); if(!fp){ Msg::Error("Unable to open file '%s'", name.c_str()); return 0; } if(noPhysicalGroups()) saveAll = true; // get the number of vertices and index the vertices in a continuous // sequence int numVertices = indexMeshVertices(saveAll); // tag the vertices according to which surface they belong to (Note // that we use a brute force approach here, so that we can deal with // models with incomplete topology. For example, when we merge 2 STL // triangulations we don't have the boundary information between the // faces, and the vertices would end up categorized on either one.) std::vector<std::list<int> > vertexTags(numVertices); std::list<int> boundaryIndicators; for(riter it = firstRegion(); it != lastRegion(); it++){ std::list<GFace*> faces = (*it)->faces(); for(std::list<GFace*>::iterator itf = faces.begin(); itf != faces.end(); itf++){ GFace *gf = *itf; boundaryIndicators.push_back(gf->tag()); for(unsigned int i = 0; i < gf->getNumMeshElements(); i++){ MElement *e = gf->getMeshElement(i); for(int j = 0; j < e->getNumVertices(); j++){ MVertex *v = e->getVertex(j); if(v->getIndex() > 0) vertexTags[v->getIndex() - 1].push_back(gf->tag()); } } } } boundaryIndicators.sort(); boundaryIndicators.unique(); for(int i = 0; i < numVertices; i++){ vertexTags[i].sort(); vertexTags[i].unique(); } // get all the entities in the model std::vector<GEntity*> entities; getEntities(entities); // find max dimension of mesh elements we need to save int dim = 0; for(unsigned int i = 0; i < entities.size(); i++) if(entities[i]->physicals.size() || saveAll) for(unsigned int j = 0; j < entities[i]->getNumMeshElements(); j++) dim = std::max(dim, entities[i]->getMeshElement(j)->getDim()); // loop over all elements we need to save int numElements = 0, maxNumNodesPerElement = 0; for(unsigned int i = 0; i < entities.size(); i++){ if(entities[i]->physicals.size() || saveAll){ for(unsigned int j = 0; j < entities[i]->getNumMeshElements(); j++){ MElement *e = entities[i]->getMeshElement(j); if(e->getStringForDIFF() && e->getDim() == dim){ numElements++; maxNumNodesPerElement = std::max(maxNumNodesPerElement, e->getNumVertices()); } } } } fprintf(fp, "\n\n"); fprintf(fp, " Finite element mesh (GridFE):\n\n"); fprintf(fp, " Number of space dim. = 3\n"); fprintf(fp, " Number of elements = %d\n", numElements); fprintf(fp, " Number of nodes = %d\n\n", numVertices); fprintf(fp, " All elements are of the same type : dpTRUE\n"); fprintf(fp, " Max number of nodes in an element: %d \n", maxNumNodesPerElement); fprintf(fp, " Only one subdomain : dpFALSE\n"); fprintf(fp, " Lattice data ? 0\n\n\n\n"); fprintf(fp, " %d Boundary indicators: ", (int)boundaryIndicators.size()); for(std::list<int>::iterator it = boundaryIndicators.begin(); it != boundaryIndicators.end(); it++) fprintf(fp, " %d", *it); fprintf(fp, "\n\n\n"); fprintf(fp," Nodal coordinates and nodal boundary indicators,\n"); fprintf(fp," the columns contain:\n"); fprintf(fp," - node number\n"); fprintf(fp," - coordinates\n"); fprintf(fp," - no of boundary indicators that are set (ON)\n"); fprintf(fp," - the boundary indicators that are set (ON) if any.\n"); fprintf(fp,"#\n"); // write mesh vertices for(unsigned int i = 0; i < entities.size(); i++){ for(unsigned int j = 0; j < entities[i]->mesh_vertices.size(); j++){ MVertex *v = entities[i]->mesh_vertices[j]; if(v->getIndex() > 0){ v->writeDIFF(fp, binary, scalingFactor); fprintf(fp, " [%d] ", (int)vertexTags[v->getIndex() - 1].size()); for(std::list<int>::iterator it = vertexTags[v->getIndex() - 1].begin(); it != vertexTags[v->getIndex() - 1].end(); it++) fprintf(fp," %d ", *it); fprintf(fp,"\n"); } } } fprintf(fp, "\n"); fprintf(fp, "\n"); fprintf(fp, " Element types and connectivity\n"); fprintf(fp, " the columns contain:\n"); fprintf(fp, " - element number\n"); fprintf(fp, " - element type\n"); fprintf(fp, " - subdomain number \n"); fprintf(fp, " - the global node numbers of the nodes in the element.\n"); fprintf(fp, "#\n"); // write mesh elements int num = 0; for(unsigned int i = 0; i < entities.size(); i++){ if(entities[i]->physicals.size() || saveAll){ for(unsigned int j = 0; j < entities[i]->getNumMeshElements(); j++){ MElement *e = entities[i]->getMeshElement(j); if(e->getStringForDIFF() && e->getDim() == dim) e->writeDIFF(fp, ++num, binary, entities[i]->tag()); } } } fprintf(fp, "\n"); fclose(fp); return 1; }
void Filler::treat_region(GRegion* gr){ int NumSmooth = CTX::instance()->mesh.smoothCrossField; std::cout << "NumSmooth = " << NumSmooth << std::endl ; if(NumSmooth && (gr->dim() == 3)){ double scale = gr->bounds().diag()*1e-2; Frame_field::initRegion(gr,NumSmooth); Frame_field::saveCrossField("cross0.pos",scale); Frame_field::smoothRegion(gr,NumSmooth); Frame_field::saveCrossField("cross1.pos",scale); } #if defined(HAVE_RTREE) unsigned int i; int j; int count; int limit; bool ok2; double x,y,z; SPoint3 point; Node *node,*individual,*parent; MVertex* vertex; MElement* element; MElementOctree* octree; deMeshGRegion deleter; Wrapper wrapper; GFace* gf; std::queue<Node*> fifo; std::vector<Node*> spawns; std::vector<Node*> garbage; std::vector<MVertex*> boundary_vertices; std::set<MVertex*> temp; std::list<GFace*> faces; std::map<MVertex*,int> limits; std::set<MVertex*>::iterator it; std::list<GFace*>::iterator it2; std::map<MVertex*,int>::iterator it3; RTree<Node*,double,3,double> rtree; Frame_field::init_region(gr); Size_field::init_region(gr); Size_field::solve(gr); octree = new MElementOctree(gr->model()); garbage.clear(); boundary_vertices.clear(); temp.clear(); new_vertices.clear(); faces.clear(); limits.clear(); faces = gr->faces(); for(it2=faces.begin();it2!=faces.end();it2++){ gf = *it2; limit = code(gf->tag()); for(i=0;i<gf->getNumMeshElements();i++){ element = gf->getMeshElement(i); for(j=0;j<element->getNumVertices();j++){ vertex = element->getVertex(j); temp.insert(vertex); limits.insert(std::pair<MVertex*,int>(vertex,limit)); } } } /*for(i=0;i<gr->getNumMeshElements();i++){ element = gr->getMeshElement(i); for(j=0;j<element->getNumVertices();j++){ vertex = element->getVertex(j); temp.insert(vertex); } }*/ for(it=temp.begin();it!=temp.end();it++){ if((*it)->onWhat()->dim()==0){ boundary_vertices.push_back(*it); } } for(it=temp.begin();it!=temp.end();it++){ if((*it)->onWhat()->dim()==1){ boundary_vertices.push_back(*it); } } for(it=temp.begin();it!=temp.end();it++){ if((*it)->onWhat()->dim()==2){ boundary_vertices.push_back(*it); } } /*for(it=temp.begin();it!=temp.end();it++){ if((*it)->onWhat()->dim()<3){ boundary_vertices.push_back(*it); } }*/ //std::ofstream file("nodes.pos"); //file << "View \"test\" {\n"; for(i=0;i<boundary_vertices.size();i++){ x = boundary_vertices[i]->x(); y = boundary_vertices[i]->y(); z = boundary_vertices[i]->z(); node = new Node(SPoint3(x,y,z)); compute_parameters(node,gr); node->set_layer(0); it3 = limits.find(boundary_vertices[i]); node->set_limit(it3->second); rtree.Insert(node->min,node->max,node); fifo.push(node); //print_node(node,file); } count = 1; while(!fifo.empty()){ parent = fifo.front(); fifo.pop(); garbage.push_back(parent); if(parent->get_limit()!=-1 && parent->get_layer()>=parent->get_limit()){ continue; } spawns.clear(); spawns.resize(6); for(i=0;i<6;i++){ spawns[i] = new Node(); } create_spawns(gr,octree,parent,spawns); for(i=0;i<6;i++){ ok2 = 0; individual = spawns[i]; point = individual->get_point(); x = point.x(); y = point.y(); z = point.z(); if(inside_domain(octree,x,y,z)){ compute_parameters(individual,gr); individual->set_layer(parent->get_layer()+1); individual->set_limit(parent->get_limit()); if(far_from_boundary(octree,individual)){ wrapper.set_ok(1); wrapper.set_individual(individual); wrapper.set_parent(parent); rtree.Search(individual->min,individual->max,rtree_callback,&wrapper); if(wrapper.get_ok()){ fifo.push(individual); rtree.Insert(individual->min,individual->max,individual); vertex = new MVertex(x,y,z,gr,0); new_vertices.push_back(vertex); ok2 = 1; //print_segment(individual->get_point(),parent->get_point(),file); } } } if(!ok2) delete individual; } if(count%100==0){ printf("%d\n",count); } count++; } //file << "};\n"; int option = CTX::instance()->mesh.algo3d; CTX::instance()->mesh.algo3d = ALGO_3D_DELAUNAY; deleter(gr); std::vector<GRegion*> regions; regions.push_back(gr); meshGRegion mesher(regions); //? mesher(gr); //? MeshDelaunayVolume(regions); CTX::instance()->mesh.algo3d = option; for(i=0;i<garbage.size();i++) delete garbage[i]; for(i=0;i<new_vertices.size();i++) delete new_vertices[i]; new_vertices.clear(); delete octree; rtree.RemoveAll(); Size_field::clear(); Frame_field::clear(); #endif }
bool computeFourNeighbors (frameFieldBackgroundMesh2D *bgm, MVertex *v_center, // the vertex for which we want to // generate 4 neighbors (real // vertex (xyz), not parametric!) SPoint2 &midpoint, bool goNonLinear, // do we compute the position in // the real surface which is // nonlinear SPoint2 newP[4][NUMDIR], // look into other directions SMetric3 &metricField) // the mesh metric { // we assume that v is on surface gf, and backgroundMesh2D has been created based on gf // get BGM and GFace GFace *gf = dynamic_cast<GFace*>(bgm->getBackgroundGEntity()); // get the parametric coordinates of the point on the surface reparamMeshVertexOnFace(v_center, gf, midpoint); // get RK info on midpoint (infos in two directions...) RK_form infos; bgm->compute_RK_infos(midpoint[0],midpoint[1],v_center->x(), v_center->y(), v_center->z(), infos); metricField = infos.metricField; // shoot in four directions SPoint2 param_vec; double h; for (int i=0;i<4;i++){// in four directions switch (i){ case 0: param_vec = infos.paramt1; h = infos.paramh.first; break; case 1: param_vec = infos.paramt2; h = infos.paramh.second; break; case 2: param_vec = infos.paramt1 * -1.; h = infos.paramh.first; break; case 3: param_vec = infos.paramt2 * -1.; h = infos.paramh.second; break; } shoot(midpoint,param_vec,h,newP[i][0]); // cout << "(" << midpoint[0] << "," <<midpoint[1] << ") -> (" << // newP[i][0][0] << "," << newP[i][0][1] << ") " << endl; } // the following comes from surfaceFiller.cpp... const double EPS = 1.e-7; for (int j=0;j<2;j++){ for (int i=0;i<4;i++){ newP[i][0][j] += (EPS* (double)rand() / RAND_MAX); } } // We could stop here. Yet, if the metric varies a lot, we can solve a // nonlinear problem in order to find a better approximation in the real // surface if (1 && goNonLinear){ double L = infos.localsize; double newPoint[4][2]; for (int j=0;j<2;j++){ for (int i=0;i<4;i++){ newPoint[i][j] = newP[i][0][j]; } } double ERR[4]; for (int i=0;i<4;i++){ // // if (newPoint[i][0] < rangeU.low())newPoint[i][0] = rangeU.low(); // if (newPoint[i][0] > rangeU.high())newPoint[i][0] = rangeU.high(); // if (newPoint[i][1] < rangeV.low())newPoint[i][1] = rangeV.low(); // if (newPoint[i][1] > rangeV.high())newPoint[i][1] = rangeV.high(); GPoint pp = gf->point(newP[i][0]); double D = sqrt ((pp.x() - v_center->x())*(pp.x() - v_center->x()) + (pp.y() - v_center->y())*(pp.y() - v_center->y()) + (pp.z() - v_center->z())*(pp.z() - v_center->z()) ); ERR[i] = 100*fabs(D-L)/(D+L); // printf("L = %12.5E D = %12.5E ERR = %12.5E\n",L,D,100*fabs(D-L)/(D+L)); } surfaceFunctorGFace ss (gf); SVector3 dirs[4] = {infos.t1*(-1.0),infos.t2*(-1.0),infos.t1*(1.0),infos.t2*(1.0)}; for (int i=0;i<4;i++){ if (ERR[i] > 12){ double uvt[3] = {newPoint[i][0],newPoint[i][1],0.0}; // printf("Intersecting with circle N = %g %g %g dir = %g %g %g R // = %g p = %g %g // %g\n",n.x(),n.y(),n.z(),dirs[i].x(),dirs[i].y(),dirs[i].z(),L, // v_center->x(),v_center->y(),v_center->z()); curveFunctorCircle cf (dirs[i],infos.normal, SVector3(v_center->x(),v_center->y(),v_center->z()), L); if (intersectCurveSurface (cf,ss,uvt,infos.paramh.first*1.e-3)){ GPoint pp = gf->point(SPoint2(uvt[0],uvt[1])); double D = sqrt ((pp.x() - v_center->x())*(pp.x() - v_center->x()) + (pp.y() - v_center->y())*(pp.y() - v_center->y()) + (pp.z() - v_center->z())*(pp.z() - v_center->z()) ); double DP = sqrt ((newPoint[i][0]-uvt[0])*(newPoint[i][0]-uvt[0]) + (newPoint[i][1]-uvt[1])*(newPoint[i][1]-uvt[1])); double newErr = 100*fabs(D-L)/(D+L); // if (v_center->onWhat() != gf && gf->tag() == 3){ // crossField2d::normalizeAngle (uvt[2]); // printf("INTERSECT angle = %g DP %g\n",uvt[2],DP); // } if (newErr < 1 && DP < .1){ // printf("%12.5E vs %12.5E : %12.5E %12.5E vs %12.5E %12.5E // \n",ERR[i],newErr,newPoint[i][0],newPoint[i][1],uvt[0],uvt[1]); newPoint[i][0] = uvt[0]; newPoint[i][1] = uvt[1]; } // printf("OK\n"); } else{ Msg::Debug("Cannot put a new point on Surface %d",gf->tag()); // printf("NOT OK\n"); } } } // return the four new vertices for (int i=0;i<4;i++){ newP[i][0] = SPoint2(newPoint[i][0],newPoint[i][1]); } } return true; }
int GModel::writeCELUM(const std::string &name, bool saveAll, double scalingFactor) { std::string namef = name + "_f"; FILE *fpf = Fopen(namef.c_str(), "w"); if(!fpf) { Msg::Error("Unable to open file '%s'", namef.c_str()); return 0; } std::string names = name + "_s"; FILE *fps = Fopen(names.c_str(), "w"); if(!fps) { Msg::Error("Unable to open file '%s'", names.c_str()); fclose(fpf); return 0; } if(noPhysicalGroups()) saveAll = true; // count faces and vertices; the CELUM format duplicates vertices on the // boundary of CAD patches int numf = 0, nums = 0; for(fiter it = firstFace(); it != lastFace(); it++) { GFace *f = *it; if(!saveAll && f->physicals.empty()) continue; numf += f->triangles.size(); std::set<MVertex *> vset; for(std::size_t i = 0; i < f->triangles.size(); i++) { for(int j = 0; j < 3; j++) vset.insert(f->triangles[i]->getVertex(j)); } nums += vset.size(); } Msg::Info("Writing %d triangles and %d vertices", numf, nums); int idf = 1, ids = 1; /* * a file with faces - number of faces - empty line ... for each face - number of the face (starts at 1 : used for read errors) - char string (name of geom part, material,... ) - list of 3 vertex nums - empty line ... * a file with vertices - number of vertices - conversion factor - empty line ... for each vertex - number of the vertex (starts at 1 : used for read errors) - cartesian coordinates of the vertex - componants of the exterior oriented normal - value of 1st principal curvature - value of second princpal curvature - components of 1st principal direction - components of 2nd principal direction - empty line ... */ fprintf(fpf, "%d\n\n", numf); fprintf(fps, "%d %g\n\n", nums, 1.0); for(fiter it = firstFace(); it != lastFace(); it++) { GFace *f = *it; if(!saveAll && f->physicals.empty()) continue; std::vector<MVertex *> vvec; std::map<MVertex *, CelumInfo> vmap; for(std::size_t i = 0; i < f->triangles.size(); i++) { fprintf(fpf, "%d \"face %d\"", idf++, f->tag()); for(int j = 0; j < 3; j++) { MVertex *v = f->triangles[i]->getVertex(j); if(!vmap.count(v)) { v->setIndex(ids++); SPoint2 param; bool ok = reparamMeshVertexOnFace(v, f, param); if(!ok) Msg::Warning("Could not reparamtrize vertex %d on face %d", v->getNum(), f->tag()); CelumInfo info; info.normal = f->normal(param); f->curvatures(param, info.dirMax, info.dirMin, info.curvMax, info.curvMin); vmap[v] = info; vvec.push_back(v); } fprintf(fpf, " %ld", v->getIndex()); } fprintf(fpf, "\n\n"); } for(std::size_t i = 0; i < vvec.size(); i++) { MVertex *v = vvec[i]; std::map<MVertex *, CelumInfo>::iterator it = vmap.find(v); fprintf(fps, "%ld %g %g %g %g %g %g %g %g %g %g %g %g %g %g\n\n", it->first->getIndex(), it->first->x(), it->first->y(), it->first->z(), it->second.normal.x(), it->second.normal.y(), it->second.normal.z(), it->second.curvMin, it->second.curvMax, it->second.dirMin.x(), it->second.dirMin.y(), it->second.dirMin.z(), it->second.dirMax.x(), it->second.dirMax.y(), it->second.dirMax.z()); } } fclose(fpf); fclose(fps); return 1; }
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; }