SMDS_MeshNode* SMESH_MesherHelper::AddNode(double x, double y, double z, int ID) { SMESHDS_Mesh * meshDS = GetMeshDS(); SMDS_MeshNode* node = 0; if ( ID ) node = meshDS->AddNodeWithID( x, y, z, ID ); else node = meshDS->AddNode( x, y, z ); if ( mySetElemOnShape && myShapeID > 0 ) { switch ( myShape.ShapeType() ) { case TopAbs_SOLID: meshDS->SetNodeInVolume( node, myShapeID); break; case TopAbs_SHELL: meshDS->SetNodeInVolume( node, myShapeID); break; case TopAbs_FACE: meshDS->SetNodeOnFace( node, myShapeID); break; case TopAbs_EDGE: meshDS->SetNodeOnEdge( node, myShapeID); break; case TopAbs_VERTEX: meshDS->SetNodeOnVertex( node, myShapeID); break; default: ; } } return node; }
//============================================================================= bool NETGENPlugin_Mesher::Compute() { #ifdef WNT netgen::MeshingParameters& mparams = netgen::GlobalMeshingParameters(); #else netgen::MeshingParameters& mparams = netgen::mparam; #endif MESSAGE("Compute with:\n" " max size = " << mparams.maxh << "\n" " segments per edge = " << mparams.segmentsperedge); MESSAGE("\n" " growth rate = " << mparams.grading << "\n" " elements per radius = " << mparams.curvaturesafety << "\n" " second order = " << mparams.secondorder << "\n" " quad allowed = " << mparams.quad); SMESH_ComputeErrorPtr error = SMESH_ComputeError::New(); nglib::Ng_Init(); // ------------------------- // Prepare OCC geometry // ------------------------- netgen::OCCGeometry occgeo; list< SMESH_subMesh* > meshedSM; PrepareOCCgeometry( occgeo, _shape, *_mesh, &meshedSM ); // ------------------------- // Generate the mesh // ------------------------- netgen::Mesh *ngMesh = NULL; SMESH_Comment comment; int err = 0; int nbInitNod = 0; int nbInitSeg = 0; int nbInitFac = 0; // vector of nodes in which node index == netgen ID vector< SMDS_MeshNode* > nodeVec; try { // ---------------- // compute 1D mesh // ---------------- // pass 1D simple parameters to NETGEN if ( _simpleHyp ) { if ( int nbSeg = _simpleHyp->GetNumberOfSegments() ) { // nb of segments mparams.segmentsperedge = nbSeg + 0.1; mparams.maxh = occgeo.boundingbox.Diam(); mparams.grading = 0.01; } else { // segment length mparams.segmentsperedge = 1; mparams.maxh = _simpleHyp->GetLocalLength(); } } // let netgen create ngMesh and calculate element size on not meshed shapes char *optstr = 0; int startWith = netgen::MESHCONST_ANALYSE; int endWith = netgen::MESHCONST_ANALYSE; err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); if (err) comment << "Error in netgen::OCCGenerateMesh() at MESHCONST_ANALYSE step"; // fill ngMesh with nodes and elements of computed submeshes err = ! fillNgMesh(occgeo, *ngMesh, nodeVec, meshedSM); nbInitNod = ngMesh->GetNP(); nbInitSeg = ngMesh->GetNSeg(); nbInitFac = ngMesh->GetNSE(); // compute mesh if (!err) { startWith = endWith = netgen::MESHCONST_MESHEDGES; err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); if (err) comment << "Error in netgen::OCCGenerateMesh() at 1D mesh generation"; } // --------------------- // compute surface mesh // --------------------- if (!err) { // pass 2D simple parameters to NETGEN if ( _simpleHyp ) { if ( double area = _simpleHyp->GetMaxElementArea() ) { // face area mparams.maxh = sqrt(2. * area/sqrt(3.0)); mparams.grading = 0.4; // moderate size growth } else { // length from edges double length = 0; TopTools_MapOfShape tmpMap; for ( TopExp_Explorer exp( _shape, TopAbs_EDGE ); exp.More(); exp.Next() ) if( tmpMap.Add(exp.Current()) ) length += SMESH_Algo::EdgeLength( TopoDS::Edge( exp.Current() )); if ( ngMesh->GetNSeg() ) { // we have to multiply length by 2 since for each TopoDS_Edge there // are double set of NETGEN edges or, in other words, we have to // divide ngMesh->GetNSeg() on 2. mparams.maxh = 2*length / ngMesh->GetNSeg(); } else mparams.maxh = 1000; mparams.grading = 0.2; // slow size growth } mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 ); ngMesh->SetGlobalH (mparams.maxh); netgen::Box<3> bb = occgeo.GetBoundingBox(); bb.Increase (bb.Diam()/20); ngMesh->SetLocalH (bb.PMin(), bb.PMax(), mparams.grading); } // let netgen compute 2D mesh startWith = netgen::MESHCONST_MESHSURFACE; endWith = _optimize ? netgen::MESHCONST_OPTSURFACE : netgen::MESHCONST_MESHSURFACE; err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); if (err) comment << "Error in netgen::OCCGenerateMesh() at surface mesh generation"; } // --------------------- // generate volume mesh // --------------------- if (!err && _isVolume) { // add ng face descriptors of meshed faces std::map< int, std::pair<int,int> >::iterator fId_soIds = _faceDescriptors.begin(); for ( ; fId_soIds != _faceDescriptors.end(); ++fId_soIds ) { int faceID = fId_soIds->first; int solidID1 = fId_soIds->second.first; int solidID2 = fId_soIds->second.second; ngMesh->AddFaceDescriptor (netgen::FaceDescriptor(faceID, solidID1, solidID2, 0)); } // pass 3D simple parameters to NETGEN const NETGENPlugin_SimpleHypothesis_3D* simple3d = dynamic_cast< const NETGENPlugin_SimpleHypothesis_3D* > ( _simpleHyp ); if ( simple3d ) { if ( double vol = simple3d->GetMaxElementVolume() ) { // max volume mparams.maxh = pow( 72, 1/6. ) * pow( vol, 1/3. ); mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 ); } else { // length from faces mparams.maxh = ngMesh->AverageH(); } // netgen::ARRAY<double> maxhdom; // maxhdom.SetSize (occgeo.NrSolids()); // maxhdom = mparams.maxh; // ngMesh->SetMaxHDomain (maxhdom); ngMesh->SetGlobalH (mparams.maxh); mparams.grading = 0.4; ngMesh->CalcLocalH(); } // let netgen compute 3D mesh startWith = netgen::MESHCONST_MESHVOLUME; endWith = _optimize ? netgen::MESHCONST_OPTVOLUME : netgen::MESHCONST_MESHVOLUME; err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); if (err) comment << "Error in netgen::OCCGenerateMesh()"; } if (!err && mparams.secondorder > 0) { netgen::OCCRefinementSurfaces ref (occgeo); ref.MakeSecondOrder (*ngMesh); } } catch (netgen::NgException exc) { error->myName = err = COMPERR_ALGO_FAILED; comment << exc.What(); } int nbNod = ngMesh->GetNP(); int nbSeg = ngMesh->GetNSeg(); int nbFac = ngMesh->GetNSE(); int nbVol = ngMesh->GetNE(); MESSAGE((err ? "Mesh Generation failure" : "End of Mesh Generation") << ", nb nodes: " << nbNod << ", nb segments: " << nbSeg << ", nb faces: " << nbFac << ", nb volumes: " << nbVol); // ----------------------------------------------------------- // Feed back the SMESHDS with the generated Nodes and Elements // ----------------------------------------------------------- SMESHDS_Mesh* meshDS = _mesh->GetMeshDS(); bool isOK = ( !err && (_isVolume ? (nbVol > 0) : (nbFac > 0)) ); if ( true /*isOK*/ ) // get whatever built { // map of nodes assigned to submeshes NCollection_Map<int> pindMap; // create and insert nodes into nodeVec nodeVec.resize( nbNod + 1 ); int i; for (i = nbInitNod+1; i <= nbNod /*&& isOK*/; ++i ) { const netgen::MeshPoint& ngPoint = ngMesh->Point(i); SMDS_MeshNode* node = NULL; bool newNodeOnVertex = false; TopoDS_Vertex aVert; if (i-nbInitNod <= occgeo.vmap.Extent()) { // point on vertex aVert = TopoDS::Vertex(occgeo.vmap(i-nbInitNod)); SMESHDS_SubMesh * submesh = meshDS->MeshElements(aVert); if (submesh) { SMDS_NodeIteratorPtr it = submesh->GetNodes(); if (it->more()) { node = const_cast<SMDS_MeshNode*> (it->next()); pindMap.Add(i); } } if (!node) newNodeOnVertex = true; } if (!node) node = meshDS->AddNode(ngPoint.X(), ngPoint.Y(), ngPoint.Z()); if (!node) { MESSAGE("Cannot create a mesh node"); if ( !comment.size() ) comment << "Cannot create a mesh node"; nbSeg = nbFac = nbVol = isOK = 0; break; } nodeVec.at(i) = node; if (newNodeOnVertex) { // point on vertex meshDS->SetNodeOnVertex(node, aVert); pindMap.Add(i); } } // create mesh segments along geometric edges NCollection_Map<Link> linkMap; for (i = nbInitSeg+1; i <= nbSeg/* && isOK*/; ++i ) { const netgen::Segment& seg = ngMesh->LineSegment(i); Link link(seg.p1, seg.p2); if (linkMap.Contains(link)) continue; linkMap.Add(link); TopoDS_Edge aEdge; int pinds[3] = { seg.p1, seg.p2, seg.pmid }; int nbp = 0; double param2 = 0; for (int j=0; j < 3; ++j) { int pind = pinds[j]; if (pind <= 0) continue; ++nbp; double param; if (j < 2) { if (aEdge.IsNull()) { int aGeomEdgeInd = seg.epgeominfo[j].edgenr; if (aGeomEdgeInd > 0 && aGeomEdgeInd <= occgeo.emap.Extent()) aEdge = TopoDS::Edge(occgeo.emap(aGeomEdgeInd)); } param = seg.epgeominfo[j].dist; param2 += param; } else param = param2 * 0.5; if (pind <= nbInitNod || pindMap.Contains(pind)) continue; if (!aEdge.IsNull()) { meshDS->SetNodeOnEdge(nodeVec.at(pind), aEdge, param); pindMap.Add(pind); } } SMDS_MeshEdge* edge; if (nbp < 3) // second order ? edge = meshDS->AddEdge(nodeVec.at(pinds[0]), nodeVec.at(pinds[1])); else edge = meshDS->AddEdge(nodeVec.at(pinds[0]), nodeVec.at(pinds[1]), nodeVec.at(pinds[2])); if (!edge) { if ( !comment.size() ) comment << "Cannot create a mesh edge"; MESSAGE("Cannot create a mesh edge"); nbSeg = nbFac = nbVol = isOK = 0; break; } if (!aEdge.IsNull()) meshDS->SetMeshElementOnShape(edge, aEdge); } // create mesh faces along geometric faces for (i = nbInitFac+1; i <= nbFac/* && isOK*/; ++i ) { const netgen::Element2d& elem = ngMesh->SurfaceElement(i); int aGeomFaceInd = elem.GetIndex(); TopoDS_Face aFace; if (aGeomFaceInd > 0 && aGeomFaceInd <= occgeo.fmap.Extent()) aFace = TopoDS::Face(occgeo.fmap(aGeomFaceInd)); vector<SMDS_MeshNode*> nodes; for (int j=1; j <= elem.GetNP(); ++j) { int pind = elem.PNum(j); SMDS_MeshNode* node = nodeVec.at(pind); nodes.push_back(node); if (pind <= nbInitNod || pindMap.Contains(pind)) continue; if (!aFace.IsNull()) { const netgen::PointGeomInfo& pgi = elem.GeomInfoPi(j); meshDS->SetNodeOnFace(node, aFace, pgi.u, pgi.v); pindMap.Add(pind); } } SMDS_MeshFace* face = NULL; switch (elem.GetType()) { case netgen::TRIG: face = meshDS->AddFace(nodes[0],nodes[1],nodes[2]); break; case netgen::QUAD: face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[3]); break; case netgen::TRIG6: face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[5],nodes[3],nodes[4]); break; case netgen::QUAD8: face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[3], nodes[4],nodes[7],nodes[5],nodes[6]); break; default: MESSAGE("NETGEN created a face of unexpected type, ignoring"); continue; } if (!face) { if ( !comment.size() ) comment << "Cannot create a mesh face"; MESSAGE("Cannot create a mesh face"); nbSeg = nbFac = nbVol = isOK = 0; break; } if (!aFace.IsNull()) meshDS->SetMeshElementOnShape(face, aFace); } // create tetrahedra for (i = 1; i <= nbVol/* && isOK*/; ++i) { const netgen::Element& elem = ngMesh->VolumeElement(i); int aSolidInd = elem.GetIndex(); TopoDS_Solid aSolid; if (aSolidInd > 0 && aSolidInd <= occgeo.somap.Extent()) aSolid = TopoDS::Solid(occgeo.somap(aSolidInd)); vector<SMDS_MeshNode*> nodes; for (int j=1; j <= elem.GetNP(); ++j) { int pind = elem.PNum(j); SMDS_MeshNode* node = nodeVec.at(pind); nodes.push_back(node); if (pind <= nbInitNod || pindMap.Contains(pind)) continue; if (!aSolid.IsNull()) { // point in solid meshDS->SetNodeInVolume(node, aSolid); pindMap.Add(pind); } } SMDS_MeshVolume* vol = NULL; switch (elem.GetType()) { case netgen::TET: vol = meshDS->AddVolume(nodes[0],nodes[1],nodes[2],nodes[3]); break; case netgen::TET10: vol = meshDS->AddVolume(nodes[0],nodes[1],nodes[2],nodes[3], nodes[4],nodes[7],nodes[5],nodes[6],nodes[8],nodes[9]); break; default: MESSAGE("NETGEN created a volume of unexpected type, ignoring"); continue; } if (!vol) { if ( !comment.size() ) comment << "Cannot create a mesh volume"; MESSAGE("Cannot create a mesh volume"); nbSeg = nbFac = nbVol = isOK = 0; break; } if (!aSolid.IsNull()) meshDS->SetMeshElementOnShape(vol, aSolid); } } if ( error->IsOK() && ( !isOK || comment.size() > 0 )) error->myName = COMPERR_ALGO_FAILED; if ( !comment.empty() ) error->myComment = comment; // set bad compute error to subshapes of all failed subshapes shapes if ( !error->IsOK() && err ) { for (int i = 1; i <= occgeo.fmap.Extent(); i++) { int status = occgeo.facemeshstatus[i-1]; if (status == 1 ) continue; if ( SMESH_subMesh* sm = _mesh->GetSubMeshContaining( occgeo.fmap( i ))) { SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); if ( !smError || smError->IsOK() ) { if ( status == -1 ) smError.reset( new SMESH_ComputeError( error->myName, error->myComment )); else smError.reset( new SMESH_ComputeError( COMPERR_ALGO_FAILED, "Ignored" )); } } } } nglib::Ng_DeleteMesh((nglib::Ng_Mesh*)ngMesh); nglib::Ng_Exit(); RemoveTmpFiles(); return error->IsOK(); }
/*! * Special function for search or creation medium node */ const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, bool force3d) { TopAbs_ShapeEnum shapeType = myShape.IsNull() ? TopAbs_SHAPE : myShape.ShapeType(); NLink link(( n1 < n2 ? n1 : n2 ), ( n1 < n2 ? n2 : n1 )); ItNLinkNode itLN = myNLinkNodeMap.find( link ); if ( itLN != myNLinkNodeMap.end() ) { return (*itLN).second; } else { // create medium node SMDS_MeshNode* n12; SMESHDS_Mesh* meshDS = GetMeshDS(); int faceID = -1, edgeID = -1; const SMDS_PositionPtr Pos1 = n1->GetPosition(); const SMDS_PositionPtr Pos2 = n2->GetPosition(); if( myShape.IsNull() ) { if( Pos1->GetTypeOfPosition()==SMDS_TOP_FACE ) { faceID = Pos1->GetShapeId(); } else if( Pos2->GetTypeOfPosition()==SMDS_TOP_FACE ) { faceID = Pos2->GetShapeId(); } if( Pos1->GetTypeOfPosition()==SMDS_TOP_EDGE ) { edgeID = Pos1->GetShapeId(); } if( Pos2->GetTypeOfPosition()==SMDS_TOP_EDGE ) { edgeID = Pos2->GetShapeId(); } } if(!force3d) { // we try to create medium node using UV parameters of // nodes, else - medium between corresponding 3d points if(faceID>-1 || shapeType == TopAbs_FACE) { // obtaining a face and 2d points for nodes TopoDS_Face F; if( myShape.IsNull() ) F = TopoDS::Face(meshDS->IndexToShape(faceID)); else { F = TopoDS::Face(myShape); faceID = myShapeID; } gp_XY p1 = GetNodeUV(F,n1,n2); gp_XY p2 = GetNodeUV(F,n2,n1); if ( IsDegenShape( Pos1->GetShapeId() )) p1.SetCoord( myParIndex, p2.Coord( myParIndex )); else if ( IsDegenShape( Pos2->GetShapeId() )) p2.SetCoord( myParIndex, p1.Coord( myParIndex )); //checking if surface is periodic Handle(Geom_Surface) S = BRep_Tool::Surface(F); Standard_Real UF,UL,VF,VL; S->Bounds(UF,UL,VF,VL); Standard_Real u,v; Standard_Boolean isUPeriodic = S->IsUPeriodic(); if(isUPeriodic) { Standard_Real UPeriod = S->UPeriod(); Standard_Real p2x = p2.X()+ShapeAnalysis::AdjustByPeriod(p2.X(),p1.X(),UPeriod); Standard_Real pmid = (p1.X()+p2x)/2.; u = pmid+ShapeAnalysis::AdjustToPeriod(pmid,UF,UL); } else u= (p1.X()+p2.X())/2.; Standard_Boolean isVPeriodic = S->IsVPeriodic(); if(isVPeriodic) { Standard_Real VPeriod = S->VPeriod(); Standard_Real p2y = p2.Y()+ShapeAnalysis::AdjustByPeriod(p2.Y(),p1.Y(),VPeriod); Standard_Real pmid = (p1.Y()+p2y)/2.; v = pmid+ShapeAnalysis::AdjustToPeriod(pmid,VF,VL); } else v = (p1.Y()+p2.Y())/2.; gp_Pnt P = S->Value(u, v); n12 = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(n12, faceID, u, v); myNLinkNodeMap.insert(NLinkNodeMap::value_type(link,n12)); return n12; } if (edgeID>-1 || shapeType == TopAbs_EDGE) { TopoDS_Edge E; if( myShape.IsNull() ) E = TopoDS::Edge(meshDS->IndexToShape(edgeID)); else { E = TopoDS::Edge(myShape); edgeID = myShapeID; } double p1 = GetNodeU(E,n1); double p2 = GetNodeU(E,n2); double f,l; Handle(Geom_Curve) C = BRep_Tool::Curve(E, f, l); if(!C.IsNull()) { Standard_Boolean isPeriodic = C->IsPeriodic(); double u; if(isPeriodic) { Standard_Real Period = C->Period(); Standard_Real p = p2+ShapeAnalysis::AdjustByPeriod(p2,p1,Period); Standard_Real pmid = (p1+p)/2.; u = pmid+ShapeAnalysis::AdjustToPeriod(pmid,C->FirstParameter(),C->LastParameter()); } else u = (p1+p2)/2.; gp_Pnt P = C->Value( u ); n12 = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnEdge(n12, edgeID, u); myNLinkNodeMap.insert(NLinkNodeMap::value_type(link,n12)); return n12; } } } // 3d variant double x = ( n1->X() + n2->X() )/2.; double y = ( n1->Y() + n2->Y() )/2.; double z = ( n1->Z() + n2->Z() )/2.; n12 = meshDS->AddNode(x,y,z); if(edgeID>-1) meshDS->SetNodeOnEdge(n12, edgeID); else if(faceID>-1) meshDS->SetNodeOnFace(n12, faceID); else meshDS->SetNodeInVolume(n12, myShapeID); myNLinkNodeMap.insert(NLinkNodeMap::value_type(link,n12)); return n12; } }
bool NETGENPlugin_NETGEN_2D_ONLY::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { MESSAGE("NETGENPlugin_NETGEN_2D_ONLY::Compute()"); SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); int faceID = meshDS->ShapeToIndex( aShape ); SMESH_MesherHelper helper(aMesh); _quadraticMesh = helper.IsQuadraticSubMesh(aShape); helper.SetElementsOnShape( true ); const bool ignoreMediumNodes = _quadraticMesh; // ------------------------ // get all edges of a face // ------------------------ const TopoDS_Face F = TopoDS::Face( aShape.Oriented( TopAbs_FORWARD )); TError problem; TSideVector wires = StdMeshers_FaceSide::GetFaceWires( F, aMesh, ignoreMediumNodes, problem ); if ( problem && !problem->IsOK() ) return error( problem ); int nbWires = wires.size(); if ( nbWires == 0 ) return error( "Problem in StdMeshers_FaceSide::GetFaceWires()"); if ( wires[0]->NbSegments() < 3 ) // ex: a circle with 2 segments return error(COMPERR_BAD_INPUT_MESH, SMESH_Comment("Too few segments: ")<<wires[0]->NbSegments()); // ------------------------- // Make input netgen mesh // ------------------------- Ng_Init(); netgen::Mesh * ngMesh = new netgen::Mesh (); netgen::OCCGeometry occgeo; NETGENPlugin_Mesher::PrepareOCCgeometry( occgeo, F, aMesh ); occgeo.fmap.Clear(); // face can be reversed, which is wrong in this case (issue 19978) occgeo.fmap.Add( F ); vector< const SMDS_MeshNode* > nodeVec; problem = AddSegmentsToMesh( *ngMesh, occgeo, wires, helper, nodeVec ); if ( problem && !problem->IsOK() ) { delete ngMesh; Ng_Exit(); return error( problem ); } // -------------------- // compute edge length // -------------------- double edgeLength = 0; if (_hypLengthFromEdges || (!_hypLengthFromEdges && !_hypMaxElementArea)) { int nbSegments = 0; for ( int iW = 0; iW < nbWires; ++iW ) { edgeLength += wires[ iW ]->Length(); nbSegments += wires[ iW ]->NbSegments(); } if ( nbSegments ) edgeLength /= nbSegments; } if ( _hypMaxElementArea ) { double maxArea = _hypMaxElementArea->GetMaxArea(); edgeLength = sqrt(2. * maxArea/sqrt(3.0)); } if ( edgeLength < DBL_MIN ) edgeLength = occgeo.GetBoundingBox().Diam(); //cout << " edgeLength = " << edgeLength << endl; netgen::mparam.maxh = edgeLength; netgen::mparam.quad = _hypQuadranglePreference ? 1 : 0; //ngMesh->SetGlobalH ( edgeLength ); // ------------------------- // Generate surface mesh // ------------------------- char *optstr = 0; int startWith = MESHCONST_MESHSURFACE; int endWith = MESHCONST_OPTSURFACE; int err = 1; try { #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100 OCC_CATCH_SIGNALS; #endif #ifdef NETGEN_V5 err = netgen::OCCGenerateMesh(occgeo, ngMesh,netgen::mparam, startWith, endWith); #else err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); #endif } catch (Standard_Failure& ex) { string comment = ex.DynamicType()->Name(); if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) { comment += ": "; comment += ex.GetMessageString(); } error(COMPERR_OCC_EXCEPTION, comment); } catch (NgException exc) { error( SMESH_Comment("NgException: ") << exc.What() ); } catch (...) { error(COMPERR_EXCEPTION,"Exception in netgen::OCCGenerateMesh()"); } // ---------------------------------------------------- // Fill the SMESHDS with the generated nodes and faces // ---------------------------------------------------- int nbNodes = ngMesh->GetNP(); int nbFaces = ngMesh->GetNSE(); int nbInputNodes = nodeVec.size(); nodeVec.resize( nbNodes, 0 ); // add nodes for ( int i = nbInputNodes + 1; i <= nbNodes; ++i ) { const MeshPoint& ngPoint = ngMesh->Point(i); SMDS_MeshNode * node = meshDS->AddNode(ngPoint(0), ngPoint(1), ngPoint(2)); nodeVec[ i-1 ] = node; } // create faces bool reverse = ( aShape.Orientation() == TopAbs_REVERSED ); for ( int i = 1; i <= nbFaces ; ++i ) { const Element2d& elem = ngMesh->SurfaceElement(i); vector<const SMDS_MeshNode*> nodes( elem.GetNP() ); for (int j=1; j <= elem.GetNP(); ++j) { int pind = elem.PNum(j); const SMDS_MeshNode* node = nodeVec.at(pind-1); if ( reverse ) nodes[ nodes.size()-j ] = node; else nodes[ j-1 ] = node; if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE ) { const PointGeomInfo& pgi = elem.GeomInfoPi(j); meshDS->SetNodeOnFace((SMDS_MeshNode*)node, faceID, pgi.u, pgi.v); } } SMDS_MeshFace* face = 0; if ( elem.GetType() == TRIG ) face = helper.AddFace(nodes[0],nodes[1],nodes[2]); else face = helper.AddFace(nodes[0],nodes[1],nodes[2],nodes[3]); } Ng_DeleteMesh((nglib::Ng_Mesh*)ngMesh); Ng_Exit(); NETGENPlugin_Mesher::RemoveTmpFiles(); return !err; }
bool StdMeshers_RadialQuadrangle_1D2D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { TopExp_Explorer exp; SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); myHelper = new SMESH_MesherHelper( aMesh ); myHelper->IsQuadraticSubMesh( aShape ); // to delete helper at exit from Compute() auto_ptr<SMESH_MesherHelper> helperDeleter( myHelper ); myLayerPositions.clear(); TopoDS_Edge CircEdge, LinEdge1, LinEdge2; int nbe = analyseFace( aShape, CircEdge, LinEdge1, LinEdge2 ); if( nbe>3 || nbe < 1 || CircEdge.IsNull() ) return error(COMPERR_BAD_SHAPE); gp_Pnt P0,P1; // points for rotation TColgp_SequenceOfPnt Points; // angles for rotation TColStd_SequenceOfReal Angles; // Nodes1 and Nodes2 - nodes along radiuses // CNodes - nodes on circle edge vector< const SMDS_MeshNode* > Nodes1, Nodes2, CNodes; SMDS_MeshNode * NC; // parameters edge nodes on face TColgp_SequenceOfPnt2d Pnts2d1; gp_Pnt2d PC; int faceID = meshDS->ShapeToIndex(aShape); TopoDS_Face F = TopoDS::Face(aShape); Handle(Geom_Surface) S = BRep_Tool::Surface(F); if(nbe==1) { Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge )); bool ok = _gen->Compute( aMesh, CircEdge ); if( !ok ) return false; map< double, const SMDS_MeshNode* > theNodes; ok = GetSortedNodesOnEdge(aMesh.GetMeshDS(),CircEdge,true,theNodes); if( !ok ) return false; CNodes.clear(); map< double, const SMDS_MeshNode* >::iterator itn = theNodes.begin(); const SMDS_MeshNode* NF = (*itn).second; CNodes.push_back( (*itn).second ); double fang = (*itn).first; if ( itn != theNodes.end() ) { itn++; for(; itn != theNodes.end(); itn++ ) { CNodes.push_back( (*itn).second ); double ang = (*itn).first - fang; if( ang>M_PI ) ang = ang - 2*M_PI; if( ang<-M_PI ) ang = ang + 2*M_PI; Angles.Append( ang ); } } P1 = gp_Pnt( NF->X(), NF->Y(), NF->Z() ); P0 = aCirc->Location(); myLayerPositions.clear(); computeLayerPositions(P0,P1); exp.Init( CircEdge, TopAbs_VERTEX ); TopoDS_Vertex V1 = TopoDS::Vertex( exp.Current() ); gp_Pnt2d p2dV = BRep_Tool::Parameters( V1, TopoDS::Face(aShape) ); NC = meshDS->AddNode(P0.X(), P0.Y(), P0.Z()); GeomAPI_ProjectPointOnSurf PPS(P0,S); double U0,V0; PPS.Parameters(1,U0,V0); meshDS->SetNodeOnFace(NC, faceID, U0, V0); PC = gp_Pnt2d(U0,V0); gp_Vec aVec(P0,P1); gp_Vec2d aVec2d(PC,p2dV); Nodes1.resize( myLayerPositions.size()+1 ); Nodes2.resize( myLayerPositions.size()+1 ); int i = 0; for(; i<myLayerPositions.size(); i++) { gp_Pnt P( P0.X() + aVec.X()*myLayerPositions[i], P0.Y() + aVec.Y()*myLayerPositions[i], P0.Z() + aVec.Z()*myLayerPositions[i] ); Points.Append(P); SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z()); Nodes1[i] = node; Nodes2[i] = node; double U = PC.X() + aVec2d.X()*myLayerPositions[i]; double V = PC.Y() + aVec2d.Y()*myLayerPositions[i]; meshDS->SetNodeOnFace( node, faceID, U, V ); Pnts2d1.Append(gp_Pnt2d(U,V)); } Nodes1[Nodes1.size()-1] = NF; Nodes2[Nodes1.size()-1] = NF; } else if(nbe==2 && LinEdge1.Orientation() != TopAbs_INTERNAL ) { // one curve must be a half of circle and other curve must be // a segment of line double fp, lp; Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge, &fp, &lp )); if( fabs(fabs(lp-fp)-M_PI) > Precision::Confusion() ) { // not half of circle return error(COMPERR_BAD_SHAPE); } Handle(Geom_Line) aLine = Handle(Geom_Line)::DownCast( getCurve( LinEdge1 )); if( aLine.IsNull() ) { // other curve not line return error(COMPERR_BAD_SHAPE); } bool linEdgeComputed = false; if( SMESH_subMesh* sm1 = aMesh.GetSubMesh(LinEdge1) ) { if( !sm1->IsEmpty() ) { if( isEdgeCompitaballyMeshed( LinEdge1, aMesh.GetSubMesh(F) )) linEdgeComputed = true; else return error("Invalid set of hypotheses"); } } bool ok = _gen->Compute( aMesh, CircEdge ); if( !ok ) return false; map< double, const SMDS_MeshNode* > theNodes; GetSortedNodesOnEdge(aMesh.GetMeshDS(),CircEdge,true,theNodes); CNodes.clear(); map< double, const SMDS_MeshNode* >::iterator itn = theNodes.begin(); double fang = (*itn).first; itn++; for(; itn != theNodes.end(); itn++ ) { CNodes.push_back( (*itn).second ); double ang = (*itn).first - fang; if( ang>M_PI ) ang = ang - 2*M_PI; if( ang<-M_PI ) ang = ang + 2*M_PI; Angles.Append( ang ); } const SMDS_MeshNode* NF = theNodes.begin()->second; const SMDS_MeshNode* NL = theNodes.rbegin()->second; CNodes.push_back( NF ); P1 = gp_Pnt( NF->X(), NF->Y(), NF->Z() ); gp_Pnt P2( NL->X(), NL->Y(), NL->Z() ); P0 = aCirc->Location(); myLayerPositions.clear(); computeLayerPositions(P0,P1); if ( linEdgeComputed ) { if (!GetSortedNodesOnEdge(aMesh.GetMeshDS(),LinEdge1,true,theNodes)) return error("Invalid mesh on a straight edge"); vector< const SMDS_MeshNode* > *pNodes1 = &Nodes1, *pNodes2 = &Nodes2; bool nodesFromP0ToP1 = ( theNodes.rbegin()->second == NF ); if ( !nodesFromP0ToP1 ) std::swap( pNodes1, pNodes2 ); map< double, const SMDS_MeshNode* >::reverse_iterator ritn = theNodes.rbegin(); itn = theNodes.begin(); for ( int i = Nodes1.size()-1; i > -1; ++itn, ++ritn, --i ) { (*pNodes1)[i] = ritn->second; (*pNodes2)[i] = itn->second; Points.Append( gpXYZ( Nodes1[i])); Pnts2d1.Append( myHelper->GetNodeUV( F, Nodes1[i])); } NC = const_cast<SMDS_MeshNode*>( itn->second ); Points.Remove( Nodes1.size() ); } else { gp_Vec aVec(P0,P1); int edgeID = meshDS->ShapeToIndex(LinEdge1); // check orientation Handle(Geom_Curve) Crv = BRep_Tool::Curve(LinEdge1,fp,lp); gp_Pnt Ptmp; Crv->D0(fp,Ptmp); bool ori = true; if( P1.Distance(Ptmp) > Precision::Confusion() ) ori = false; // get UV points for edge gp_Pnt2d PF,PL; BRep_Tool::UVPoints( LinEdge1, TopoDS::Face(aShape), PF, PL ); PC = gp_Pnt2d( (PF.X()+PL.X())/2, (PF.Y()+PL.Y())/2 ); gp_Vec2d V2d; if(ori) V2d = gp_Vec2d(PC,PF); else V2d = gp_Vec2d(PC,PL); // add nodes on edge double cp = (fp+lp)/2; double dp2 = (lp-fp)/2; NC = meshDS->AddNode(P0.X(), P0.Y(), P0.Z()); meshDS->SetNodeOnEdge(NC, edgeID, cp); Nodes1.resize( myLayerPositions.size()+1 ); Nodes2.resize( myLayerPositions.size()+1 ); int i = 0; for(; i<myLayerPositions.size(); i++) { gp_Pnt P( P0.X() + aVec.X()*myLayerPositions[i], P0.Y() + aVec.Y()*myLayerPositions[i], P0.Z() + aVec.Z()*myLayerPositions[i] ); Points.Append(P); SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z()); Nodes1[i] = node; double param; if(ori) param = fp + dp2*(1-myLayerPositions[i]); else param = cp + dp2*myLayerPositions[i]; meshDS->SetNodeOnEdge(node, edgeID, param); P = gp_Pnt( P0.X() - aVec.X()*myLayerPositions[i], P0.Y() - aVec.Y()*myLayerPositions[i], P0.Z() - aVec.Z()*myLayerPositions[i] ); node = meshDS->AddNode(P.X(), P.Y(), P.Z()); Nodes2[i] = node; if(!ori) param = fp + dp2*(1-myLayerPositions[i]); else param = cp + dp2*myLayerPositions[i]; meshDS->SetNodeOnEdge(node, edgeID, param); // parameters on face gp_Pnt2d P2d( PC.X() + V2d.X()*myLayerPositions[i], PC.Y() + V2d.Y()*myLayerPositions[i] ); Pnts2d1.Append(P2d); } Nodes1[ myLayerPositions.size() ] = NF; Nodes2[ myLayerPositions.size() ] = NL; // create 1D elements on edge vector< const SMDS_MeshNode* > tmpNodes; tmpNodes.resize(2*Nodes1.size()+1); for(i=0; i<Nodes2.size(); i++) tmpNodes[Nodes2.size()-i-1] = Nodes2[i]; tmpNodes[Nodes2.size()] = NC; for(i=0; i<Nodes1.size(); i++) tmpNodes[Nodes2.size()+1+i] = Nodes1[i]; for(i=1; i<tmpNodes.size(); i++) { SMDS_MeshEdge* ME = myHelper->AddEdge( tmpNodes[i-1], tmpNodes[i] ); if(ME) meshDS->SetMeshElementOnShape(ME, edgeID); } markLinEdgeAsComputedByMe( LinEdge1, aMesh.GetSubMesh( F )); } } else // nbe==3 or ( nbe==2 && linEdge is INTERNAL ) { if (nbe==2 && LinEdge1.Orientation() == TopAbs_INTERNAL ) LinEdge2 = LinEdge1; // one curve must be a part of circle and other curves must be // segments of line double fp, lp; Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge )); Handle(Geom_Line) aLine1 = Handle(Geom_Line)::DownCast( getCurve( LinEdge1 )); Handle(Geom_Line) aLine2 = Handle(Geom_Line)::DownCast( getCurve( LinEdge2 )); if( aLine1.IsNull() || aLine2.IsNull() ) { // other curve not line return error(COMPERR_BAD_SHAPE); } bool linEdge1Computed = false; if ( SMESH_subMesh* sm1 = aMesh.GetSubMesh(LinEdge1)) if( !sm1->IsEmpty() ) { if( isEdgeCompitaballyMeshed( LinEdge1, aMesh.GetSubMesh(F) )) linEdge1Computed = true; else return error("Invalid set of hypotheses"); } bool linEdge2Computed = false; if ( SMESH_subMesh* sm2 = aMesh.GetSubMesh(LinEdge2)) if( !sm2->IsEmpty() ) { if( isEdgeCompitaballyMeshed( LinEdge2, aMesh.GetSubMesh(F) )) linEdge2Computed = true; else return error("Invalid set of hypotheses"); } bool ok = _gen->Compute( aMesh, CircEdge ); if( !ok ) return false; map< double, const SMDS_MeshNode* > theNodes; GetSortedNodesOnEdge(aMesh.GetMeshDS(),CircEdge,true,theNodes); const SMDS_MeshNode* NF = theNodes.begin()->second; const SMDS_MeshNode* NL = theNodes.rbegin()->second; CNodes.clear(); CNodes.push_back( NF ); map< double, const SMDS_MeshNode* >::iterator itn = theNodes.begin(); double fang = (*itn).first; itn++; for(; itn != theNodes.end(); itn++ ) { CNodes.push_back( (*itn).second ); double ang = (*itn).first - fang; if( ang>M_PI ) ang = ang - 2*M_PI; if( ang<-M_PI ) ang = ang + 2*M_PI; Angles.Append( ang ); } P1 = gp_Pnt( NF->X(), NF->Y(), NF->Z() ); gp_Pnt P2( NL->X(), NL->Y(), NL->Z() ); P0 = aCirc->Location(); myLayerPositions.clear(); computeLayerPositions(P0,P1); Nodes1.resize( myLayerPositions.size()+1 ); Nodes2.resize( myLayerPositions.size()+1 ); exp.Init( LinEdge1, TopAbs_VERTEX ); TopoDS_Vertex V1 = TopoDS::Vertex( exp.Current() ); exp.Next(); TopoDS_Vertex V2 = TopoDS::Vertex( exp.Current() ); gp_Pnt PE1 = BRep_Tool::Pnt(V1); gp_Pnt PE2 = BRep_Tool::Pnt(V2); if( ( P1.Distance(PE1) > Precision::Confusion() ) && ( P1.Distance(PE2) > Precision::Confusion() ) ) { std::swap( LinEdge1, LinEdge2 ); std::swap( linEdge1Computed, linEdge2Computed ); } TopoDS_Vertex VC = V2; if( ( P1.Distance(PE1) > Precision::Confusion() ) && ( P2.Distance(PE1) > Precision::Confusion() ) ) VC = V1; int vertID = meshDS->ShapeToIndex(VC); // LinEdge1 if ( linEdge1Computed ) { if (!GetSortedNodesOnEdge(aMesh.GetMeshDS(),LinEdge1,true,theNodes)) return error("Invalid mesh on a straight edge"); bool nodesFromP0ToP1 = ( theNodes.rbegin()->second == NF ); NC = const_cast<SMDS_MeshNode*> ( nodesFromP0ToP1 ? theNodes.begin()->second : theNodes.rbegin()->second ); int i = 0, ir = Nodes1.size()-1; int * pi = nodesFromP0ToP1 ? &i : &ir; itn = theNodes.begin(); if ( nodesFromP0ToP1 ) ++itn; for ( ; i < Nodes1.size(); ++i, --ir, ++itn ) { Nodes1[*pi] = itn->second; } for ( i = 0; i < Nodes1.size()-1; ++i ) { Points.Append( gpXYZ( Nodes1[i])); Pnts2d1.Append( myHelper->GetNodeUV( F, Nodes1[i])); } } else { int edgeID = meshDS->ShapeToIndex(LinEdge1); gp_Vec aVec(P0,P1); // check orientation Handle(Geom_Curve) Crv = BRep_Tool::Curve(LinEdge1,fp,lp); gp_Pnt Ptmp = Crv->Value(fp); bool ori = false; if( P1.Distance(Ptmp) > Precision::Confusion() ) ori = true; // get UV points for edge gp_Pnt2d PF,PL; BRep_Tool::UVPoints( LinEdge1, TopoDS::Face(aShape), PF, PL ); gp_Vec2d V2d; if(ori) { V2d = gp_Vec2d(PF,PL); PC = PF; } else { V2d = gp_Vec2d(PL,PF); PC = PL; } NC = const_cast<SMDS_MeshNode*>( VertexNode( VC, meshDS )); if ( !NC ) { NC = meshDS->AddNode(P0.X(), P0.Y(), P0.Z()); meshDS->SetNodeOnVertex(NC, vertID); } double dp = lp-fp; int i = 0; for(; i<myLayerPositions.size(); i++) { gp_Pnt P( P0.X() + aVec.X()*myLayerPositions[i], P0.Y() + aVec.Y()*myLayerPositions[i], P0.Z() + aVec.Z()*myLayerPositions[i] ); Points.Append(P); SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z()); Nodes1[i] = node; double param; if(!ori) param = fp + dp*(1-myLayerPositions[i]); else param = fp + dp*myLayerPositions[i]; meshDS->SetNodeOnEdge(node, edgeID, param); // parameters on face gp_Pnt2d P2d( PC.X() + V2d.X()*myLayerPositions[i], PC.Y() + V2d.Y()*myLayerPositions[i] ); Pnts2d1.Append(P2d); } Nodes1[ myLayerPositions.size() ] = NF; // create 1D elements on edge SMDS_MeshEdge* ME = myHelper->AddEdge( NC, Nodes1[0] ); if(ME) meshDS->SetMeshElementOnShape(ME, edgeID); for(i=1; i<Nodes1.size(); i++) { ME = myHelper->AddEdge( Nodes1[i-1], Nodes1[i] ); if(ME) meshDS->SetMeshElementOnShape(ME, edgeID); } if (nbe==2 && LinEdge1.Orientation() == TopAbs_INTERNAL ) Nodes2 = Nodes1; } markLinEdgeAsComputedByMe( LinEdge1, aMesh.GetSubMesh( F )); // LinEdge2 if ( linEdge2Computed ) { if (!GetSortedNodesOnEdge(aMesh.GetMeshDS(),LinEdge2,true,theNodes)) return error("Invalid mesh on a straight edge"); bool nodesFromP0ToP2 = ( theNodes.rbegin()->second == NL ); int i = 0, ir = Nodes1.size()-1; int * pi = nodesFromP0ToP2 ? &i : &ir; itn = theNodes.begin(); if ( nodesFromP0ToP2 ) ++itn; for ( ; i < Nodes2.size(); ++i, --ir, ++itn ) Nodes2[*pi] = itn->second; } else { int edgeID = meshDS->ShapeToIndex(LinEdge2); gp_Vec aVec = gp_Vec(P0,P2); // check orientation Handle(Geom_Curve) Crv = BRep_Tool::Curve(LinEdge2,fp,lp); gp_Pnt Ptmp = Crv->Value(fp); bool ori = false; if( P2.Distance(Ptmp) > Precision::Confusion() ) ori = true; // get UV points for edge gp_Pnt2d PF,PL; BRep_Tool::UVPoints( LinEdge2, TopoDS::Face(aShape), PF, PL ); gp_Vec2d V2d; if(ori) { V2d = gp_Vec2d(PF,PL); PC = PF; } else { V2d = gp_Vec2d(PL,PF); PC = PL; } double dp = lp-fp; for(int i=0; i<myLayerPositions.size(); i++) { gp_Pnt P( P0.X() + aVec.X()*myLayerPositions[i], P0.Y() + aVec.Y()*myLayerPositions[i], P0.Z() + aVec.Z()*myLayerPositions[i] ); SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z()); Nodes2[i] = node; double param; if(!ori) param = fp + dp*(1-myLayerPositions[i]); else param = fp + dp*myLayerPositions[i]; meshDS->SetNodeOnEdge(node, edgeID, param); // parameters on face gp_Pnt2d P2d( PC.X() + V2d.X()*myLayerPositions[i], PC.Y() + V2d.Y()*myLayerPositions[i] ); } Nodes2[ myLayerPositions.size() ] = NL; // create 1D elements on edge SMDS_MeshEdge* ME = myHelper->AddEdge( NC, Nodes2[0] ); if(ME) meshDS->SetMeshElementOnShape(ME, edgeID); for(int i=1; i<Nodes2.size(); i++) { ME = myHelper->AddEdge( Nodes2[i-1], Nodes2[i] ); if(ME) meshDS->SetMeshElementOnShape(ME, edgeID); } } markLinEdgeAsComputedByMe( LinEdge2, aMesh.GetSubMesh( F )); } // orientation bool IsForward = ( CircEdge.Orientation()==TopAbs_FORWARD ); // create nodes and mesh elements on face // find axis of rotation gp_Pnt P2 = gp_Pnt( CNodes[1]->X(), CNodes[1]->Y(), CNodes[1]->Z() ); gp_Vec Vec1(P0,P1); gp_Vec Vec2(P0,P2); gp_Vec Axis = Vec1.Crossed(Vec2); // create elements int i = 1; //cout<<"Angles.Length() = "<<Angles.Length()<<" Points.Length() = "<<Points.Length()<<endl; //cout<<"Nodes1.size() = "<<Nodes1.size()<<" Pnts2d1.Length() = "<<Pnts2d1.Length()<<endl; for(; i<Angles.Length(); i++) { vector< const SMDS_MeshNode* > tmpNodes; tmpNodes.reserve(Nodes1.size()); gp_Trsf aTrsf; gp_Ax1 theAxis(P0,gp_Dir(Axis)); aTrsf.SetRotation( theAxis, Angles.Value(i) ); gp_Trsf2d aTrsf2d; aTrsf2d.SetRotation( PC, Angles.Value(i) ); // create nodes int j = 1; for(; j<=Points.Length(); j++) { double cx,cy,cz; Points.Value(j).Coord( cx, cy, cz ); aTrsf.Transforms( cx, cy, cz ); SMDS_MeshNode* node = myHelper->AddNode( cx, cy, cz ); // find parameters on face Pnts2d1.Value(j).Coord( cx, cy ); aTrsf2d.Transforms( cx, cy ); // set node on face meshDS->SetNodeOnFace( node, faceID, cx, cy ); tmpNodes[j-1] = node; } // create faces tmpNodes[Points.Length()] = CNodes[i]; // quad for(j=0; j<Nodes1.size()-1; j++) { SMDS_MeshFace* MF; if(IsForward) MF = myHelper->AddFace( tmpNodes[j], Nodes1[j], Nodes1[j+1], tmpNodes[j+1] ); else MF = myHelper->AddFace( tmpNodes[j], tmpNodes[j+1], Nodes1[j+1], Nodes1[j] ); if(MF) meshDS->SetMeshElementOnShape(MF, faceID); } // tria SMDS_MeshFace* MF; if(IsForward) MF = myHelper->AddFace( NC, Nodes1[0], tmpNodes[0] ); else MF = myHelper->AddFace( NC, tmpNodes[0], Nodes1[0] ); if(MF) meshDS->SetMeshElementOnShape(MF, faceID); for(j=0; j<Nodes1.size(); j++) { Nodes1[j] = tmpNodes[j]; } } // create last faces // quad for(i=0; i<Nodes1.size()-1; i++) { SMDS_MeshFace* MF; if(IsForward) MF = myHelper->AddFace( Nodes2[i], Nodes1[i], Nodes1[i+1], Nodes2[i+1] ); else MF = myHelper->AddFace( Nodes2[i], Nodes2[i+1], Nodes1[i+1], Nodes1[i] ); if(MF) meshDS->SetMeshElementOnShape(MF, faceID); } // tria SMDS_MeshFace* MF; if(IsForward) MF = myHelper->AddFace( NC, Nodes1[0], Nodes2[0] ); else MF = myHelper->AddFace( NC, Nodes2[0], Nodes1[0] ); if(MF) meshDS->SetMeshElementOnShape(MF, faceID); return true; }
bool NETGENPlugin_NETGEN_2D_ONLY::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { netgen::multithread.terminate = 0; //netgen::multithread.task = "Surface meshing"; SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); SMESH_MesherHelper helper(aMesh); helper.SetElementsOnShape( true ); NETGENPlugin_NetgenLibWrapper ngLib; ngLib._isComputeOk = false; netgen::Mesh ngMeshNoLocSize; #if NETGEN_VERSION < 6 netgen::Mesh * ngMeshes[2] = { (netgen::Mesh*) ngLib._ngMesh, & ngMeshNoLocSize }; #else netgen::Mesh * ngMeshes[2] = { (netgen::Mesh*) ngLib._ngMesh.get(), & ngMeshNoLocSize }; #endif netgen::OCCGeometry occgeoComm; // min / max sizes are set as follows: // if ( _hypParameters ) // min and max are defined by the user // else if ( _hypLengthFromEdges ) // min = aMesher.GetDefaultMinSize() // max = average segment len of a FACE // else if ( _hypMaxElementArea ) // min = aMesher.GetDefaultMinSize() // max = f( _hypMaxElementArea ) // else // min = aMesher.GetDefaultMinSize() // max = max segment len of a FACE NETGENPlugin_Mesher aMesher( &aMesh, aShape, /*isVolume=*/false); aMesher.SetParameters( _hypParameters ); // _hypParameters -> netgen::mparam const bool toOptimize = _hypParameters ? _hypParameters->GetOptimize() : true; if ( _hypMaxElementArea ) { netgen::mparam.maxh = sqrt( 2. * _hypMaxElementArea->GetMaxArea() / sqrt(3.0) ); } if ( _hypQuadranglePreference ) netgen::mparam.quad = true; // local size is common for all FACEs in aShape? const bool isCommonLocalSize = ( !_hypLengthFromEdges && !_hypMaxElementArea && netgen::mparam.uselocalh ); const bool isDefaultHyp = ( !_hypLengthFromEdges && !_hypMaxElementArea && !_hypParameters ); if ( isCommonLocalSize ) // compute common local size in ngMeshes[0] { //list< SMESH_subMesh* > meshedSM[4]; --> all sub-shapes are added to occgeoComm aMesher.PrepareOCCgeometry( occgeoComm, aShape, aMesh );//, meshedSM ); // local size set at MESHCONST_ANALYSE step depends on // minh, face_maxh, grading and curvaturesafety; find minh if not set by the user if ( !_hypParameters || netgen::mparam.minh < DBL_MIN ) { if ( !_hypParameters ) netgen::mparam.maxh = occgeoComm.GetBoundingBox().Diam() / 3.; netgen::mparam.minh = aMesher.GetDefaultMinSize( aShape, netgen::mparam.maxh ); } // set local size depending on curvature and NOT closeness of EDGEs netgen::occparam.resthcloseedgeenable = false; //netgen::occparam.resthcloseedgefac = 1.0 + netgen::mparam.grading; occgeoComm.face_maxh = netgen::mparam.maxh; netgen::OCCSetLocalMeshSize( occgeoComm, *ngMeshes[0] ); occgeoComm.emap.Clear(); occgeoComm.vmap.Clear(); // set local size according to size of existing segments const double factor = netgen::occparam.resthcloseedgefac; TopTools_IndexedMapOfShape edgeMap; TopExp::MapShapes( aMesh.GetShapeToMesh(), TopAbs_EDGE, edgeMap ); for ( int iE = 1; iE <= edgeMap.Extent(); ++iE ) { const TopoDS_Shape& edge = edgeMap( iE ); if ( SMESH_Algo::isDegenerated( TopoDS::Edge( edge ))/* || helper.IsSubShape( edge, aShape )*/) continue; SMESHDS_SubMesh* smDS = meshDS->MeshElements( edge ); if ( !smDS ) continue; SMDS_ElemIteratorPtr segIt = smDS->GetElements(); while ( segIt->more() ) { const SMDS_MeshElement* seg = segIt->next(); SMESH_TNodeXYZ n1 = seg->GetNode(0); SMESH_TNodeXYZ n2 = seg->GetNode(1); gp_XYZ p = 0.5 * ( n1 + n2 ); netgen::Point3d pi(p.X(), p.Y(), p.Z()); ngMeshes[0]->RestrictLocalH( pi, factor * ( n1 - n2 ).Modulus() ); } } } netgen::mparam.uselocalh = toOptimize; // restore as it is used at surface optimization // ================== // Loop on all FACEs // ================== vector< const SMDS_MeshNode* > nodeVec; TopExp_Explorer fExp( aShape, TopAbs_FACE ); for ( int iF = 0; fExp.More(); fExp.Next(), ++iF ) { TopoDS_Face F = TopoDS::Face( fExp.Current() /*.Oriented( TopAbs_FORWARD )*/); int faceID = meshDS->ShapeToIndex( F ); SMESH_ComputeErrorPtr& faceErr = aMesh.GetSubMesh( F )->GetComputeError(); _quadraticMesh = helper.IsQuadraticSubMesh( F ); const bool ignoreMediumNodes = _quadraticMesh; // build viscous layers if required if ( F.Orientation() != TopAbs_FORWARD && F.Orientation() != TopAbs_REVERSED ) F.Orientation( TopAbs_FORWARD ); // avoid pb with TopAbs_INTERNAL SMESH_ProxyMesh::Ptr proxyMesh = StdMeshers_ViscousLayers2D::Compute( aMesh, F ); if ( !proxyMesh ) continue; // ------------------------ // get all EDGEs of a FACE // ------------------------ TSideVector wires = StdMeshers_FaceSide::GetFaceWires( F, aMesh, ignoreMediumNodes, faceErr, proxyMesh ); if ( faceErr && !faceErr->IsOK() ) continue; int nbWires = wires.size(); if ( nbWires == 0 ) { faceErr.reset ( new SMESH_ComputeError ( COMPERR_ALGO_FAILED, "Problem in StdMeshers_FaceSide::GetFaceWires()" )); continue; } if ( wires[0]->NbSegments() < 3 ) // ex: a circle with 2 segments { faceErr.reset ( new SMESH_ComputeError ( COMPERR_BAD_INPUT_MESH, SMESH_Comment("Too few segments: ")<<wires[0]->NbSegments()) ); continue; } // ---------------------- // compute maxh of a FACE // ---------------------- if ( !_hypParameters ) { double edgeLength = 0; if (_hypLengthFromEdges ) { // compute edgeLength as an average segment length int nbSegments = 0; for ( int iW = 0; iW < nbWires; ++iW ) { edgeLength += wires[ iW ]->Length(); nbSegments += wires[ iW ]->NbSegments(); } if ( nbSegments ) edgeLength /= nbSegments; netgen::mparam.maxh = edgeLength; } else if ( isDefaultHyp ) { // set edgeLength by a longest segment double maxSeg2 = 0; for ( int iW = 0; iW < nbWires; ++iW ) { const UVPtStructVec& points = wires[ iW ]->GetUVPtStruct(); if ( points.empty() ) return error( COMPERR_BAD_INPUT_MESH ); gp_Pnt pPrev = SMESH_TNodeXYZ( points[0].node ); for ( size_t i = 1; i < points.size(); ++i ) { gp_Pnt p = SMESH_TNodeXYZ( points[i].node ); maxSeg2 = Max( maxSeg2, p.SquareDistance( pPrev )); pPrev = p; } } edgeLength = sqrt( maxSeg2 ) * 1.05; netgen::mparam.maxh = edgeLength; } if ( netgen::mparam.maxh < DBL_MIN ) netgen::mparam.maxh = occgeoComm.GetBoundingBox().Diam(); if ( !isCommonLocalSize ) { netgen::mparam.minh = aMesher.GetDefaultMinSize( F, netgen::mparam.maxh ); } } // prepare occgeom netgen::OCCGeometry occgeom; occgeom.shape = F; occgeom.fmap.Add( F ); occgeom.CalcBoundingBox(); occgeom.facemeshstatus.SetSize(1); occgeom.facemeshstatus = 0; occgeom.face_maxh_modified.SetSize(1); occgeom.face_maxh_modified = 0; occgeom.face_maxh.SetSize(1); occgeom.face_maxh = netgen::mparam.maxh; // ------------------------- // Fill netgen mesh // ------------------------- // MESHCONST_ANALYSE step may lead to a failure, so we make an attempt // w/o MESHCONST_ANALYSE at the second loop int err = 0; enum { LOC_SIZE, NO_LOC_SIZE }; int iLoop = isCommonLocalSize ? 0 : 1; for ( ; iLoop < 2; iLoop++ ) { //bool isMESHCONST_ANALYSE = false; InitComputeError(); netgen::Mesh * ngMesh = ngMeshes[ iLoop ]; ngMesh->DeleteMesh(); if ( iLoop == NO_LOC_SIZE ) { ngMesh->SetGlobalH ( mparam.maxh ); ngMesh->SetMinimalH( mparam.minh ); Box<3> bb = occgeom.GetBoundingBox(); bb.Increase (bb.Diam()/10); ngMesh->SetLocalH (bb.PMin(), bb.PMax(), mparam.grading); } nodeVec.clear(); faceErr = aMesher.AddSegmentsToMesh( *ngMesh, occgeom, wires, helper, nodeVec, /*overrideMinH=*/!_hypParameters); if ( faceErr && !faceErr->IsOK() ) break; //if ( !isCommonLocalSize ) //limitSize( ngMesh, mparam.maxh * 0.8); // ------------------------- // Generate surface mesh // ------------------------- const int startWith = MESHCONST_MESHSURFACE; const int endWith = toOptimize ? MESHCONST_OPTSURFACE : MESHCONST_MESHSURFACE; SMESH_Comment str; try { OCC_CATCH_SIGNALS; #if NETGEN_VERSION >=6 std::shared_ptr<netgen::Mesh> mesh_ptr(ngMesh, [](netgen::Mesh*) {}); err = netgen::OCCGenerateMesh(occgeom, mesh_ptr, netgen::mparam, startWith, endWith); #elif NETGEN_VERSION > 4 err = netgen::OCCGenerateMesh(occgeom, ngMesh, netgen::mparam, startWith, endWith); #else char *optstr = 0; err = netgen::OCCGenerateMesh(occgeom, ngMesh, startWith, endWith, optstr); #endif if ( netgen::multithread.terminate ) return false; if ( err ) str << "Error in netgen::OCCGenerateMesh() at " << netgen::multithread.task; } catch (Standard_Failure& ex) { err = 1; str << "Exception in netgen::OCCGenerateMesh()" << " at " << netgen::multithread.task << ": " << ex.DynamicType()->Name(); if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) str << ": " << ex.GetMessageString(); } catch (...) { err = 1; str << "Exception in netgen::OCCGenerateMesh()" << " at " << netgen::multithread.task; } if ( err ) { if ( aMesher.FixFaceMesh( occgeom, *ngMesh, 1 )) break; if ( iLoop == LOC_SIZE ) { netgen::mparam.minh = netgen::mparam.maxh; netgen::mparam.maxh = 0; for ( int iW = 0; iW < wires.size(); ++iW ) { StdMeshers_FaceSidePtr wire = wires[ iW ]; const vector<UVPtStruct>& uvPtVec = wire->GetUVPtStruct(); for ( size_t iP = 1; iP < uvPtVec.size(); ++iP ) { SMESH_TNodeXYZ p( uvPtVec[ iP ].node ); netgen::Point3d np( p.X(),p.Y(),p.Z()); double segLen = p.Distance( uvPtVec[ iP-1 ].node ); double size = ngMesh->GetH( np ); netgen::mparam.minh = Min( netgen::mparam.minh, size ); netgen::mparam.maxh = Max( netgen::mparam.maxh, segLen ); } } //cerr << "min " << netgen::mparam.minh << " max " << netgen::mparam.maxh << endl; netgen::mparam.minh *= 0.9; netgen::mparam.maxh *= 1.1; continue; } else { faceErr.reset( new SMESH_ComputeError( COMPERR_ALGO_FAILED, str )); } } // ---------------------------------------------------- // Fill the SMESHDS with the generated nodes and faces // ---------------------------------------------------- int nbNodes = ngMesh->GetNP(); int nbFaces = ngMesh->GetNSE(); int nbInputNodes = nodeVec.size()-1; nodeVec.resize( nbNodes+1, 0 ); // add nodes for ( int ngID = nbInputNodes + 1; ngID <= nbNodes; ++ngID ) { const MeshPoint& ngPoint = ngMesh->Point( ngID ); SMDS_MeshNode * node = meshDS->AddNode(ngPoint(0), ngPoint(1), ngPoint(2)); nodeVec[ ngID ] = node; } // create faces int i,j; vector<const SMDS_MeshNode*> nodes; for ( i = 1; i <= nbFaces ; ++i ) { const Element2d& elem = ngMesh->SurfaceElement(i); nodes.resize( elem.GetNP() ); for (j=1; j <= elem.GetNP(); ++j) { int pind = elem.PNum(j); if ( pind < 1 ) break; nodes[ j-1 ] = nodeVec[ pind ]; if ( nodes[ j-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE ) { const PointGeomInfo& pgi = elem.GeomInfoPi(j); meshDS->SetNodeOnFace( nodes[ j-1 ], faceID, pgi.u, pgi.v); } } if ( j > elem.GetNP() ) { SMDS_MeshFace* face = 0; if ( elem.GetType() == TRIG ) face = helper.AddFace(nodes[0],nodes[1],nodes[2]); else face = helper.AddFace(nodes[0],nodes[1],nodes[2],nodes[3]); } } break; } // two attempts } // loop on FACEs return true; }