SMDS_MeshEdge* SMESH_MesherHelper::AddEdge(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const int id, const bool force3d) { SMESHDS_Mesh * meshDS = GetMeshDS(); SMDS_MeshEdge* edge = 0; if (myCreateQuadratic) { const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d); if(id) edge = meshDS->AddEdgeWithID(n1, n2, n12, id); else edge = meshDS->AddEdge(n1, n2, n12); } else { if(id) edge = meshDS->AddEdgeWithID(n1, n2, id); else edge = meshDS->AddEdge(n1, n2); } if ( mySetElemOnShape && myShapeID > 0 ) meshDS->SetMeshElementOnShape( edge, myShapeID ); return edge; }
PyObject* FemMeshPy::addEdge(PyObject *args) { int n1,n2; if (!PyArg_ParseTuple(args, "ii",&n1,&n2)) return 0; try { SMESH_Mesh* mesh = getFemMeshPtr()->getSMesh(); SMESHDS_Mesh* meshDS = mesh->GetMeshDS(); const SMDS_MeshNode* node1 = meshDS->FindNode(n1); const SMDS_MeshNode* node2 = meshDS->FindNode(n2); if (!node1 || !node2) throw std::runtime_error("Failed to get node of the given indices"); SMDS_MeshEdge* edge = meshDS->AddEdge(node1, node2); if (!edge) throw std::runtime_error("Failed to add edge"); return Py::new_reference_to(Py::Int(edge->GetID())); } catch (const std::exception& e) { PyErr_SetString(PyExc_Exception, e.what()); return 0; } }
//============================================================================= 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(); }
PyObject* FemMeshPy::addEdge(PyObject *args) { SMESH_Mesh* mesh = getFemMeshPtr()->getSMesh(); SMESHDS_Mesh* meshDS = mesh->GetMeshDS(); int n1,n2; if (PyArg_ParseTuple(args, "ii",&n1,&n2)) { try { const SMDS_MeshNode* node1 = meshDS->FindNode(n1); const SMDS_MeshNode* node2 = meshDS->FindNode(n2); if (!node1 || !node2) throw std::runtime_error("Failed to get node of the given indices"); SMDS_MeshEdge* edge = meshDS->AddEdge(node1, node2); if (!edge) throw std::runtime_error("Failed to add edge"); return Py::new_reference_to(Py::Long(edge->GetID())); } catch (const std::exception& e) { PyErr_SetString(Base::BaseExceptionFreeCADError, e.what()); return 0; } } PyErr_Clear(); PyObject *obj; int ElementId=-1; if (PyArg_ParseTuple(args, "O!|i", &PyList_Type, &obj, &ElementId)) { Py::List list(obj); std::vector<const SMDS_MeshNode*> Nodes; for (Py::List::iterator it = list.begin(); it != list.end(); ++it) { #if PY_MAJOR_VERSION >= 3 Py::Long NoNr(*it); #else Py::Int NoNr(*it); #endif const SMDS_MeshNode* node = meshDS->FindNode(NoNr); if (!node) throw std::runtime_error("Failed to get node of the given indices"); Nodes.push_back(node); } SMDS_MeshEdge* edge=0; if(ElementId != -1) { switch(Nodes.size()){ case 2: edge = meshDS->AddEdgeWithID(Nodes[0],Nodes[1],ElementId); if (!edge) throw std::runtime_error("Failed to add edge with given ElementId"); break; case 3: edge = meshDS->AddEdgeWithID(Nodes[0],Nodes[1],Nodes[2],ElementId); if (!edge) throw std::runtime_error("Failed to add edge with given ElementId"); break; default: throw std::runtime_error("Unknown node count, [2|3] are allowed"); //unknown edge type } } else { switch(Nodes.size()){ case 2: edge = meshDS->AddEdge(Nodes[0],Nodes[1]); if (!edge) throw std::runtime_error("Failed to add edge"); break; case 3: edge = meshDS->AddEdge(Nodes[0],Nodes[1],Nodes[2]); if (!edge) throw std::runtime_error("Failed to add edge"); break; default: throw std::runtime_error("Unknown node count, [2|3] are allowed"); //unknown edge type } } #if PY_MAJOR_VERSION >= 3 return Py::new_reference_to(Py::Long(edge->GetID())); #else return Py::new_reference_to(Py::Int(edge->GetID())); #endif } PyErr_SetString(PyExc_TypeError, "addEdge accepts:\n" "-- int,int\n" "-- [2|3],[int]\n"); return 0; }
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; }