// this function specifically meshes a quadToTri top in an unstructured way // return 1 if success, return 0 if failed. // Added 2010-12-20 static int MeshQuadToTriTopUnstructured(GFace *from, GFace *to, std::set<MVertex*, MVertexLessThanLexicographic> &pos) { // if the source is all triangles, then just return 1. if( from->triangles.size() && !from->quadrangles.size() ) return 1; if( !to->meshAttributes.extrude || !to->meshAttributes.extrude->mesh.QuadToTri ) return 0; // in weird case of NO quads and NO tri if( !from->triangles.size() && !from->quadrangles.size() ) return 0; // make set of source edge vertices std::set<MVertex*, MVertexLessThanLexicographic> pos_src_edge; QuadToTriInsertFaceEdgeVertices(from, pos_src_edge); // Loop through all the quads and make the triangles with diagonals running // in a selected direction. to->triangles.reserve(to->triangles.size()+from->quadrangles.size()*2); std::set<MVertex*, MVertexLessThanLexicographic>::iterator itp; for(unsigned int i = 0; i < from->quadrangles.size(); i++){ std::vector<MVertex*> verts; for(int j = 0; j < from->quadrangles[i]->getNumVertices(); j++){ MVertex *v = from->quadrangles[i]->getVertex(j); MVertex tmp(v->x(), v->y(), v->z(), 0, -1); ExtrudeParams *ep = to->meshAttributes.extrude; ep->Extrude(ep->mesh.NbLayer - 1, ep->mesh.NbElmLayer[ep->mesh.NbLayer - 1], tmp.x(), tmp.y(), tmp.z()); itp = pos.find(&tmp); if(itp == pos.end()){ // FIXME: workaround Msg::Info("Linear search for (%.16g, %.16g, %.16g)", tmp.x(), tmp.y(), tmp.z()); itp = tmp.linearSearch(pos); } if(itp == pos.end()) { Msg::Error("Could not find extruded vertex (%.16g, %.16g, %.16g) in surface %d", tmp.x(), tmp.y(), tmp.z(), to->tag()); to->triangles.reserve(to->triangles.size()+1); return 0; } verts.push_back(*itp); } if( verts.size() != 4 ){ Msg::Error("During mesh of QuadToTri surface %d, %d vertices found " "in quad of source surface %d.", to->tag(), verts.size(), from->tag() ); return 0; } // draw other diagonals to minimize difference in average edge length with diagonal length, in quadrature double mag_sq_ave = 0.0; for( int p = 0; p < 4; p++ ){ int d_leg = verts[p]->distance(verts[(p+1)%4]); mag_sq_ave += d_leg*d_leg; } mag_sq_ave /= 4; double d1 = verts[0]->distance(verts[2]); double d2 = verts[1]->distance(verts[3]); if(fabs(d1*d1-mag_sq_ave) <= fabs(d2*d2-mag_sq_ave) ){ addTriangle(verts[0],verts[1],verts[2],to); addTriangle(verts[0],verts[2],verts[3],to); } else{ addTriangle(verts[1],verts[2],verts[3],to); addTriangle(verts[1],verts[3],verts[0],to); } } return 1; }
// This function meshes the top surface of a QuadToTri extrusion. It returns 0 if it is given a // non-quadToTri extrusion or if it fails. // Args: // 'GFace *to' is the top surface to mesh, 'from' is the source surface, 'pos' is a std::set // of vertex positions for the top surface. int MeshQuadToTriTopSurface( GFace *from, GFace *to, std::set<MVertex*, MVertexLessThanLexicographic> &pos ) { if( !to->meshAttributes.extrude || !to->meshAttributes.extrude->mesh.QuadToTri ) return 0; // if the source is all triangles, then just let this function is not needed. Return 1. if( from->triangles.size() && !from->quadrangles.size() ) return 1; // in weird case of NO quads and NO tri if( !from->triangles.size() && !from->quadrangles.size() ) return 0; ExtrudeParams *ep = to->meshAttributes.extrude; if( !ep || !ep->mesh.ExtrudeMesh || !(ep->geo.Mode == COPIED_ENTITY) ){ Msg::Error("In MeshQuadToTriTopSurface(), incomplete or no " "extrude information for top face %d.", to->tag() ); return 0; } // is this a quadtri extrusion with added vertices? bool is_addverts = false; if( ep && (ep->mesh.QuadToTri == QUADTRI_ADDVERTS_1 || ep->mesh.QuadToTri == QUADTRI_ADDVERTS_1_RECOMB) ) is_addverts = true; // execute this section if // IF this is a 'no new vertices' quadToTri, mesh the surfaces according to this modified // least point value method: if a 3 boundary point quad, draw diagonals from middle corner toward // interior. If a a 2- or 1- point boundary quad, draw toward lowest pointer number NOT on boundary. // All interior quad, draw diagonal to vertex with lowest pointer number. if( !is_addverts ){ std::set<MVertex*, MVertexLessThanLexicographic> pos_src_edge; QuadToTriInsertFaceEdgeVertices(from, pos_src_edge); std::set<MVertex*, MVertexLessThanLexicographic>::iterator itp; // loop through each element source quadrangle and extrude for(unsigned int i = 0; i < from->quadrangles.size(); i++){ std::vector<MVertex*> verts; for(int j = 0; j < from->quadrangles[i]->getNumVertices(); j++){ MVertex *v = from->quadrangles[i]->getVertex(j); MVertex tmp(v->x(), v->y(), v->z(), 0, -1); ExtrudeParams *ep = to->meshAttributes.extrude; ep->Extrude(ep->mesh.NbLayer - 1, ep->mesh.NbElmLayer[ep->mesh.NbLayer - 1], tmp.x(), tmp.y(), tmp.z()); itp = pos.find(&tmp); if(itp == pos.end()){ // FIXME: workaround Msg::Info("Linear search for (%.16g, %.16g, %.16g)", tmp.x(), tmp.y(), tmp.z()); itp = tmp.linearSearch(pos); } if(itp == pos.end()) { Msg::Error("In MeshQuadToTriTopSurface(), Could not find " "extruded vertex (%.16g, %.16g, %.16g) in surface %d", tmp.x(), tmp.y(), tmp.z(), to->tag()); to->triangles.reserve(to->triangles.size()+1); return 0; } verts.push_back(*itp); } if( verts.size() != 4 ){ Msg::Error("During mesh of QuadToTri surface %d, %d vertices found " "in quad of source surface %d.", to->tag(), verts.size(), from->tag() ); return 0; } // make the element MElement *element = from->quadrangles[i]; // count vertices that are on a boundary edge int edge_verts_count = 0; //int skip_index = 0; int bnd_indices[4]; for( int p = 0; p < element->getNumVertices(); p++ ){ if( pos_src_edge.find( element->getVertex(p) ) != pos_src_edge.end() ){ edge_verts_count++; bnd_indices[p] = 1; } else{ //skip_index = p; bnd_indices[p] = 0; } } // Apply modified lowest vertex pointer diagonalization int low_index = -1; if( edge_verts_count == 3 || edge_verts_count == 2 || edge_verts_count == 1 ){ for( int p = 0; p < 4; p++ ){ if( !bnd_indices[p] && verts[p] != element->getVertex(p) ){ if( low_index < 0 ) low_index = p; else if( verts[p] < verts[low_index] ) low_index = p; } } if( low_index < 0 ) // what if they are all degenerate? Avoid the out-of-bounds error. low_index = 0; } // lowest possible vertex pointer, regardless of if on edge or not else if( edge_verts_count == 4 || edge_verts_count == 0 ) low_index = getIndexForLowestVertexPointer(verts); addTriangle( verts[low_index],verts[(low_index+1)%verts.size()], verts[(low_index+2)%verts.size()],to); addTriangle( verts[low_index],verts[(low_index+2)%verts.size()], verts[(low_index+3)%verts.size()],to); } return 1; } // AFTER THIS POINT IN FUNCTION, CODE IS ALL FOR 'ADD INTERNAL VERTEX' EXTRUSIONS (Less restrictive). // if source face is unstructured, can try to make the top mesh a little neater GFace *root_source = findRootSourceFaceForFace( from ); ExtrudeParams *ep_src = root_source->meshAttributes.extrude; bool struct_root = false; if( root_source && ( (ep_src && ep_src->mesh.ExtrudeMesh && ep_src->geo.Mode == EXTRUDED_ENTITY) || root_source->meshAttributes.method == MESH_TRANSFINITE ) ) struct_root = true; if( !struct_root && MeshQuadToTriTopUnstructured(from, to, pos) ) return 1; // And top surface for the 'added internal vertex' method can be meshed quite easily else{ std::set<MVertex *, MVertexLessThanLexicographic >::iterator itp; // loop through each element source quadrangle and extrude for(unsigned int i = 0; i < from->quadrangles.size(); i++){ std::vector<MVertex*> verts; for(int j = 0; j < from->quadrangles[i]->getNumVertices(); j++){ MVertex *v = from->quadrangles[i]->getVertex(j); MVertex tmp(v->x(), v->y(), v->z(), 0, -1); ExtrudeParams *ep = to->meshAttributes.extrude; ep->Extrude(ep->mesh.NbLayer - 1, ep->mesh.NbElmLayer[ep->mesh.NbLayer - 1], tmp.x(), tmp.y(), tmp.z()); itp = pos.find(&tmp); if(itp == pos.end()){ // FIXME: workaround Msg::Info("Linear search for (%.16g, %.16g, %.16g)", tmp.x(), tmp.y(), tmp.z()); itp = tmp.linearSearch(pos); } if(itp == pos.end()) { Msg::Error("In MeshQuadToTriTopSurface(), Could not find " "extruded vertex (%.16g, %.16g, %.16g) in surface %d", tmp.x(), tmp.y(), tmp.z(), to->tag()); to->triangles.reserve(to->triangles.size()+1); return 0; } verts.push_back(*itp); } if( verts.size() != 4 ){ Msg::Error("During mesh of QuadToTri surface %d, %d vertices found " "in quad of source surface %d.", to->tag(), verts.size(), from->tag() ); return 0; } // make the elements addTriangle( verts[0],verts[2], verts[3],to); addTriangle( verts[0],verts[1], verts[2],to); } return 1; } return 0; }
static void extrudeMesh(GFace *from, GRegion *to, MVertexRTree &pos) { ExtrudeParams *ep = to->meshAttributes.extrude; // interior vertices std::vector<MVertex*> mesh_vertices = from->mesh_vertices; // add all embedded vertices std::vector<MVertex*> embedded = from->getEmbeddedMeshVertices(); mesh_vertices.insert(mesh_vertices.end(), embedded.begin(), embedded.end()); // create extruded vertices for(unsigned int i = 0; i < mesh_vertices.size(); i++){ MVertex *v = mesh_vertices[i]; for(int j = 0; j < ep->mesh.NbLayer; j++) { for(int k = 0; k < ep->mesh.NbElmLayer[j]; k++) { double x = v->x(), y = v->y(), z = v->z(); ep->Extrude(j, k + 1, x, y, z); if(j != ep->mesh.NbLayer - 1 || k != ep->mesh.NbElmLayer[j] - 1){ MVertex *newv = new MVertex(x, y, z, to); to->mesh_vertices.push_back(newv); pos.insert(newv); } } } } if(ep && ep->mesh.ExtrudeMesh && ep->mesh.QuadToTri && ep->mesh.Recombine){ meshQuadToTriRegion(to, pos); return; } // create elements (note that it would be faster to access the *interior* // nodes by direct indexing, but it's just simpler to query everything by // position) for(unsigned int i = 0; i < from->triangles.size(); i++){ for(int j = 0; j < ep->mesh.NbLayer; j++) { for(int k = 0; k < ep->mesh.NbElmLayer[j]; k++) { std::vector<MVertex*> verts; if(getExtrudedVertices(from->triangles[i], ep, j, k, pos, verts) == 6) { createPriPyrTet(verts, to,from->triangles[i]); } } } } if(from->quadrangles.size() && !ep->mesh.Recombine){ Msg::Error("Cannot extrude quadrangles without Recombine"); } else{ for(unsigned int i = 0; i < from->quadrangles.size(); i++){ for(int j = 0; j < ep->mesh.NbLayer; j++) { for(int k = 0; k < ep->mesh.NbElmLayer[j]; k++) { std::vector<MVertex*> verts; if(getExtrudedVertices(from->quadrangles[i], ep, j, k, pos, verts) == 8) createHexPri(verts, to, from->quadrangles[i]); } } } } }