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(); }
bool StdMeshers_CompositeSegment_1D::Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape) { TopoDS_Edge edge = TopoDS::Edge( aShape ); SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); // Get edges to be discretized as a whole TopoDS_Face nullFace; auto_ptr< StdMeshers_FaceSide > side( GetFaceSide(aMesh, edge, nullFace, true )); //side->dump("IN COMPOSITE SEG"); if ( side->NbEdges() < 2 ) return StdMeshers_Regular_1D::Compute( aMesh, aShape ); // update segment lenght computed by StdMeshers_AutomaticLength const list <const SMESHDS_Hypothesis * > & hyps = GetUsedHypothesis(aMesh, aShape); if ( !hyps.empty() ) { StdMeshers_AutomaticLength * autoLenHyp = const_cast<StdMeshers_AutomaticLength *> (dynamic_cast <const StdMeshers_AutomaticLength * >(hyps.front())); if ( autoLenHyp ) _value[ BEG_LENGTH_IND ]= autoLenHyp->GetLength( &aMesh, side->Length() ); } // Compute node parameters auto_ptr< BRepAdaptor_CompCurve > C3d ( side->GetCurve3d() ); double f = C3d->FirstParameter(), l = C3d->LastParameter(); list< double > params; if ( !computeInternalParameters ( aMesh, *C3d, side->Length(), f, l, params, false )) return false; // Redistribute parameters near ends TopoDS_Vertex VFirst = side->FirstVertex(); TopoDS_Vertex VLast = side->LastVertex(); redistributeNearVertices( aMesh, *C3d, side->Length(), params, VFirst, VLast ); params.push_front(f); params.push_back(l); int nbNodes = params.size(); // Create mesh const SMDS_MeshNode * nFirst = SMESH_Algo::VertexNode( VFirst, meshDS ); const SMDS_MeshNode * nLast = SMESH_Algo::VertexNode( VLast, meshDS ); if (!nFirst) return error(COMPERR_BAD_INPUT_MESH, TComm("No node on vertex ") <<meshDS->ShapeToIndex(VFirst)); if (!nLast) return error(COMPERR_BAD_INPUT_MESH, TComm("No node on vertex ") <<meshDS->ShapeToIndex(VLast)); vector<const SMDS_MeshNode*> nodes( nbNodes, (const SMDS_MeshNode*)0 ); nodes.front() = nFirst; nodes.back() = nLast; // create internal nodes list< double >::iterator parIt = params.begin(); double prevPar = *parIt; Standard_Real u; for ( int iN = 0; parIt != params.end(); ++iN, ++parIt) { if ( !nodes[ iN ] ) { gp_Pnt p = C3d->Value( *parIt ); SMDS_MeshNode* n = meshDS->AddNode( p.X(), p.Y(), p.Z()); C3d->Edge( *parIt, edge, u ); meshDS->SetNodeOnEdge( n, edge, u ); // cout << "new NODE: par="<<*parIt<<" ePar="<<u<<" e="<<edge.TShape().operator->() // << " " << n << endl; nodes[ iN ] = n; } // create edges if ( iN ) { double mPar = ( prevPar + *parIt )/2; if ( _quadraticMesh ) { // create medium node double segLen = GCPnts_AbscissaPoint::Length(*C3d, prevPar, *parIt); GCPnts_AbscissaPoint ruler( *C3d, segLen/2., prevPar ); if ( ruler.IsDone() ) mPar = ruler.Parameter(); gp_Pnt p = C3d->Value( mPar ); SMDS_MeshNode* n = meshDS->AddNode( p.X(), p.Y(), p.Z()); //cout << "new NODE "<< n << endl; meshDS->SetNodeOnEdge( n, edge, u ); SMDS_MeshEdge * seg = meshDS->AddEdge(nodes[ iN-1 ], nodes[ iN ], n); meshDS->SetMeshElementOnShape(seg, edge); } else { C3d->Edge( mPar, edge, u ); SMDS_MeshEdge * seg = meshDS->AddEdge(nodes[ iN-1 ], nodes[ iN ]); meshDS->SetMeshElementOnShape(seg, edge); } } prevPar = *parIt; } // remove nodes on internal vertices for ( int iE = 1; iE < side->NbEdges(); ++iE ) { TopoDS_Vertex V = side->FirstVertex( iE ); while ( const SMDS_MeshNode * n = SMESH_Algo::VertexNode( V, meshDS )) meshDS->RemoveNode( n ); } // Update submeshes state for all edges and internal vertices, // make them look computed even if none edge or node is set on them careOfSubMeshes( *side, _EventListener ); return true; }
/*! * 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 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; }