1 // Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // NETGENPlugin : C++ implementation
23 // File : NETGENPlugin_Mesher.cxx
24 // Author : Michael Sazonov (OCN)
27 //=============================================================================
29 #include "NETGENPlugin_Mesher.hxx"
30 #include "NETGENPlugin_Hypothesis_2D.hxx"
31 #include "NETGENPlugin_SimpleHypothesis_3D.hxx"
33 #include <SMESH_Mesh.hxx>
34 #include <SMESH_Comment.hxx>
35 #include <SMESH_ComputeError.hxx>
36 #include <SMESH_subMesh.hxx>
37 #include <SMESH_MesherHelper.hxx>
38 #include <SMESHDS_Mesh.hxx>
39 #include <SMDS_MeshElement.hxx>
40 #include <SMDS_MeshNode.hxx>
41 #include <utilities.h>
45 #include <BRep_Tool.hxx>
47 #include <TopExp_Explorer.hxx>
49 #include <NCollection_Map.hxx>
50 #include <OSD_Path.hxx>
51 #include <OSD_File.hxx>
52 #include <TCollection_AsciiString.hxx>
53 #include <TopTools_ListIteratorOfListOfShape.hxx>
54 #include <Standard_ErrorHandler.hxx>
56 // Netgen include files
61 #include <occgeom.hpp>
62 #include <meshing.hpp>
63 //#include <ngexception.hpp>
65 extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, int, int, char*);
66 extern MeshingParameters mparam;
71 //=============================================================================
75 //=============================================================================
77 NETGENPlugin_Mesher::NETGENPlugin_Mesher (SMESH_Mesh* mesh,
78 const TopoDS_Shape& aShape,
89 //================================================================================
91 * \brief Initialize global NETGEN parameters with default values
93 //================================================================================
95 void NETGENPlugin_Mesher::defaultParameters()
98 netgen::MeshingParameters& mparams = netgen::GlobalMeshingParameters();
100 netgen::MeshingParameters& mparams = netgen::mparam;
102 // maximal mesh edge size
103 mparams.maxh = NETGENPlugin_Hypothesis::GetDefaultMaxSize();
104 // minimal number of segments per edge
105 mparams.segmentsperedge = NETGENPlugin_Hypothesis::GetDefaultNbSegPerEdge();
106 // rate of growth of size between elements
107 mparams.grading = NETGENPlugin_Hypothesis::GetDefaultGrowthRate();
108 // safety factor for curvatures (elements per radius)
109 mparams.curvaturesafety = NETGENPlugin_Hypothesis::GetDefaultNbSegPerRadius();
110 // create elements of second order
111 mparams.secondorder = NETGENPlugin_Hypothesis::GetDefaultSecondOrder() ? 1 : 0;
112 // quad-dominated surface meshing
116 mparams.quad = NETGENPlugin_Hypothesis_2D::GetDefaultQuadAllowed() ? 1 : 0;
119 //=============================================================================
121 * Pass parameters to NETGEN
123 //=============================================================================
124 void NETGENPlugin_Mesher::SetParameters(const NETGENPlugin_Hypothesis* hyp)
129 netgen::MeshingParameters& mparams = netgen::GlobalMeshingParameters();
131 netgen::MeshingParameters& mparams = netgen::mparam;
133 // Initialize global NETGEN parameters:
134 // maximal mesh segment size
135 mparams.maxh = hyp->GetMaxSize();
136 // minimal number of segments per edge
137 mparams.segmentsperedge = hyp->GetNbSegPerEdge();
138 // rate of growth of size between elements
139 mparams.grading = hyp->GetGrowthRate();
140 // safety factor for curvatures (elements per radius)
141 mparams.curvaturesafety = hyp->GetNbSegPerRadius();
142 // create elements of second order
143 mparams.secondorder = hyp->GetSecondOrder() ? 1 : 0;
144 // quad-dominated surface meshing
145 // only triangles are allowed for volumic mesh
147 mparams.quad = static_cast<const NETGENPlugin_Hypothesis_2D*>
148 (hyp)->GetQuadAllowed() ? 1 : 0;
149 _optimize = hyp->GetOptimize();
154 //=============================================================================
156 * Pass simple parameters to NETGEN
158 //=============================================================================
160 void NETGENPlugin_Mesher::SetParameters(const NETGENPlugin_SimpleHypothesis_2D* hyp)
167 //=============================================================================
169 * Link - a pair of integer numbers
171 //=============================================================================
175 Link(int _n1, int _n2) : n1(_n1), n2(_n2) {}
176 Link() : n1(0), n2(0) {}
179 int HashCode(const Link& aLink, int aLimit)
181 return HashCode(aLink.n1 + aLink.n2, aLimit);
184 Standard_Boolean IsEqual(const Link& aLink1, const Link& aLink2)
186 return (aLink1.n1 == aLink2.n1 && aLink1.n2 == aLink2.n2 ||
187 aLink1.n1 == aLink2.n2 && aLink1.n2 == aLink2.n1);
190 //================================================================================
192 * \brief Initialize netgen::OCCGeometry with OCCT shape
194 //================================================================================
196 void NETGENPlugin_Mesher::PrepareOCCgeometry(netgen::OCCGeometry& occgeo,
197 const TopoDS_Shape& shape,
199 list< SMESH_subMesh* > * meshedSM)
201 BRepTools::Clean (shape);
203 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
206 BRepMesh_IncrementalMesh::BRepMesh_IncrementalMesh (shape, 0.01, true);
207 } catch (Standard_Failure) {
210 BRepBndLib::Add (shape, bb);
211 double x1,y1,z1,x2,y2,z2;
212 bb.Get (x1,y1,z1,x2,y2,z2);
213 MESSAGE("shape bounding box:\n" <<
214 "(" << x1 << " " << y1 << " " << z1 << ") " <<
215 "(" << x2 << " " << y2 << " " << z2 << ")");
216 netgen::Point<3> p1 = netgen::Point<3> (x1,y1,z1);
217 netgen::Point<3> p2 = netgen::Point<3> (x2,y2,z2);
218 occgeo.boundingbox = netgen::Box<3> (p1,p2);
220 occgeo.shape = shape;
222 //occgeo.BuildFMap();
224 // fill maps of shapes of occgeo with not yet meshed subshapes
226 // get root submeshes
227 list< SMESH_subMesh* > rootSM;
228 if ( SMESH_subMesh* sm = mesh.GetSubMeshContaining( shape )) {
229 rootSM.push_back( sm );
232 for ( TopoDS_Iterator it( shape ); it.More(); it.Next() )
233 rootSM.push_back( mesh.GetSubMesh( it.Value() ));
236 // add subshapes of empty submeshes
237 list< SMESH_subMesh* >::iterator rootIt = rootSM.begin(), rootEnd = rootSM.end();
238 for ( ; rootIt != rootEnd; ++rootIt ) {
239 SMESH_subMesh * root = *rootIt;
240 SMESH_subMeshIteratorPtr smIt = root->getDependsOnIterator(/*includeSelf=*/true,
241 /*complexShapeFirst=*/true);
242 // to find a right orientation of subshapes (PAL20462)
243 TopTools_IndexedMapOfShape subShapes;
244 TopExp::MapShapes(root->GetSubShape(), subShapes);
245 while ( smIt->more() ) {
246 SMESH_subMesh* sm = smIt->next();
247 if ( sm->IsEmpty() ) {
248 TopoDS_Shape shape = sm->GetSubShape();
249 if ( shape.ShapeType() != TopAbs_VERTEX )
250 shape = subShapes( subShapes.FindIndex( shape ));// - shape->index->oriented shape
251 switch ( shape.ShapeType() ) {
252 case TopAbs_FACE : occgeo.fmap.Add( shape ); break;
253 case TopAbs_EDGE : occgeo.emap.Add( shape ); break;
254 case TopAbs_VERTEX: occgeo.vmap.Add( shape ); break;
255 case TopAbs_SOLID :occgeo.somap.Add( shape ); break;
259 // collect submeshes of meshed shapes
261 meshedSM->push_back( sm );
265 occgeo.facemeshstatus.SetSize (occgeo.fmap.Extent());
266 occgeo.facemeshstatus = 0;
270 //================================================================================
272 * \brief return id of netgen point corresponding to SMDS node
274 //================================================================================
275 typedef map< const SMDS_MeshNode*, int > TNode2IdMap;
277 static int ngNodeId( const SMDS_MeshNode* node,
278 netgen::Mesh& ngMesh,
279 TNode2IdMap& nodeNgIdMap)
281 int newNgId = ngMesh.GetNP() + 1;
283 pair< TNode2IdMap::iterator, bool > it_isNew = nodeNgIdMap.insert( make_pair( node, newNgId ));
285 if ( it_isNew.second ) {
286 netgen::MeshPoint p( netgen::Point<3> (node->X(), node->Y(), node->Z()) );
287 ngMesh.AddPoint( p );
289 return it_isNew.first->second;
292 //================================================================================
294 * \brief fill ngMesh with nodes and elements of computed submeshes
296 //================================================================================
298 bool NETGENPlugin_Mesher::fillNgMesh(netgen::OCCGeometry& occgeom,
299 netgen::Mesh& ngMesh,
300 vector<SMDS_MeshNode*>& nodeVec,
301 const list< SMESH_subMesh* > & meshedSM)
303 TNode2IdMap nodeNgIdMap;
305 TopTools_MapOfShape visitedShapes;
307 SMESH_MesherHelper helper (*_mesh);
309 int faceID = occgeom.fmap.Extent();
310 _faceDescriptors.clear();
312 list< SMESH_subMesh* >::const_iterator smIt, smEnd = meshedSM.end();
313 for ( smIt = meshedSM.begin(); smIt != smEnd; ++smIt )
315 SMESH_subMesh* sm = *smIt;
316 if ( !visitedShapes.Add( sm->GetSubShape() ))
319 SMESHDS_SubMesh * smDS = sm->GetSubMeshDS();
321 switch ( sm->GetSubShape().ShapeType() )
323 case TopAbs_EDGE: { // EDGE
324 // ----------------------
325 const TopoDS_Edge& geomEdge = TopoDS::Edge( sm->GetSubShape() );
327 // Add ng segments for each not meshed face the edge bounds
328 TopTools_MapOfShape visitedAncestors;
329 const TopTools_ListOfShape& ancestors = _mesh->GetAncestors( geomEdge );
330 TopTools_ListIteratorOfListOfShape ancestorIt ( ancestors );
331 for ( ; ancestorIt.More(); ancestorIt.Next() )
333 const TopoDS_Shape & ans = ancestorIt.Value();
334 if ( ans.ShapeType() != TopAbs_FACE || !visitedAncestors.Add( ans ))
336 const TopoDS_Face& face = TopoDS::Face( ans );
338 int faceID = occgeom.fmap.FindIndex( face );
340 continue; // meshed face
342 // find out orientation of geomEdge within face
343 bool isForwad = false;
344 for ( TopExp_Explorer exp( face, TopAbs_EDGE ); exp.More(); exp.Next() ) {
345 if ( geomEdge.IsSame( exp.Current() )) {
346 isForwad = ( exp.Current().Orientation() == geomEdge.Orientation() );
350 bool isQuad = smDS->GetElements()->next()->IsQuadratic();
352 // get all nodes from geomEdge
353 StdMeshers_FaceSide fSide( face, geomEdge, _mesh, isForwad, isQuad );
354 const vector<UVPtStruct>& points = fSide.GetUVPtStruct();
355 int i, nbSeg = fSide.NbSegments();
357 double otherSeamParam = 0;
358 helper.SetSubShape( face );
359 bool isSeam = helper.IsRealSeam( geomEdge );
362 helper.GetOtherParam( helper.GetPeriodicIndex() == 1 ? points[0].u : points[0].v );
366 int prevNgId = ngNodeId( points[0].node, ngMesh, nodeNgIdMap );
368 for ( i = 0; i < nbSeg; ++i )
370 const UVPtStruct& p1 = points[ i ];
371 const UVPtStruct& p2 = points[ i+1 ];
376 seg.p2 = prevNgId = ngNodeId( p2.node, ngMesh, nodeNgIdMap );
377 // node param on curve
378 seg.epgeominfo[ 0 ].dist = p1.param;
379 seg.epgeominfo[ 1 ].dist = p2.param;
381 seg.epgeominfo[ 0 ].u = p1.u;
382 seg.epgeominfo[ 0 ].v = p1.v;
383 seg.epgeominfo[ 1 ].u = p2.u;
384 seg.epgeominfo[ 1 ].v = p2.v;
386 //seg.epgeominfo[ iEnd ].edgenr = edgeID; // = geom.emap.FindIndex(edge);
387 seg.si = faceID; // = geom.fmap.FindIndex (face);
388 seg.edgenr = ngMesh.GetNSeg() + 1; // segment id
389 ngMesh.AddSegment (seg);
393 if ( helper.GetPeriodicIndex() == 1 ) {
394 seg.epgeominfo[ 0 ].u = otherSeamParam;
395 seg.epgeominfo[ 1 ].u = otherSeamParam;
396 swap (seg.epgeominfo[0].v, seg.epgeominfo[1].v);
398 seg.epgeominfo[ 0 ].v = otherSeamParam;
399 seg.epgeominfo[ 1 ].v = otherSeamParam;
400 swap (seg.epgeominfo[0].u, seg.epgeominfo[1].u);
402 swap (seg.p1, seg.p2);
403 swap (seg.epgeominfo[0].dist, seg.epgeominfo[1].dist);
404 seg.edgenr = ngMesh.GetNSeg() + 1; // segment id
405 ngMesh.AddSegment (seg);
408 } // loop on geomEdge ancestors
411 } // case TopAbs_EDGE
413 case TopAbs_FACE: { // FACE
414 // ----------------------
415 const TopoDS_Face& geomFace = TopoDS::Face( sm->GetSubShape() );
416 helper.SetSubShape( geomFace );
418 // Find solids the geomFace bounds
419 int solidID1 = 0, solidID2 = 0;
420 const TopTools_ListOfShape& ancestors = _mesh->GetAncestors( geomFace );
421 TopTools_ListIteratorOfListOfShape ancestorIt ( ancestors );
422 for ( ; ancestorIt.More(); ancestorIt.Next() )
424 const TopoDS_Shape & solid = ancestorIt.Value();
425 if ( solid.ShapeType() == TopAbs_SOLID ) {
426 int id = occgeom.somap.FindIndex ( solid );
427 if ( solidID1 && id != solidID1 ) solidID2 = id;
432 _faceDescriptors[ faceID ].first = solidID1;
433 _faceDescriptors[ faceID ].second = solidID2;
435 // Orient the face correctly in solidID1 (issue 0020206)
436 bool reverse = false;
438 TopoDS_Shape solid = occgeom.somap( solidID1 );
439 for ( TopExp_Explorer f( solid, TopAbs_FACE ); f.More(); f.Next() ) {
440 if ( geomFace.IsSame( f.Current() )) {
441 reverse = SMESH_Algo::IsReversedSubMesh( TopoDS::Face( f.Current()), helper.GetMeshDS() );
447 // Add surface elements
448 SMDS_ElemIteratorPtr faces = smDS->GetElements();
449 while ( faces->more() ) {
451 const SMDS_MeshElement* f = faces->next();
452 if ( f->NbNodes() % 3 != 0 ) { // not triangle
453 for ( ancestorIt.Initialize(ancestors); ancestorIt.More(); ancestorIt.Next() )
454 if ( ancestorIt.Value().ShapeType() == TopAbs_SOLID ) {
455 sm = _mesh->GetSubMesh( ancestorIt.Value() );
458 SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
459 smError.reset( new SMESH_ComputeError(COMPERR_BAD_INPUT_MESH,"Not triangle submesh"));
460 smError->myBadElements.push_back( f );
464 netgen::Element2d tri(3);
465 tri.SetIndex ( faceID );
467 for ( int i = 0; i < 3; ++i ) {
468 const SMDS_MeshNode* node = f->GetNode( i ), * inFaceNode=0;
469 if ( helper.IsSeamShape( node->GetPosition()->GetShapeId() ))
470 if ( helper.IsSeamShape( f->GetNodeWrap( i+1 )->GetPosition()->GetShapeId() ))
471 inFaceNode = f->GetNodeWrap( i-1 );
473 inFaceNode = f->GetNodeWrap( i+1 );
475 gp_XY uv = helper.GetNodeUV( geomFace, node, inFaceNode );
477 tri.GeomInfoPi(3-i).u = uv.X();
478 tri.GeomInfoPi(3-i).v = uv.Y();
479 tri.PNum (3-i) = ngNodeId( node, ngMesh, nodeNgIdMap );
481 tri.GeomInfoPi(i+1).u = uv.X();
482 tri.GeomInfoPi(i+1).v = uv.Y();
483 tri.PNum (i+1) = ngNodeId( node, ngMesh, nodeNgIdMap );
487 ngMesh.AddSurfaceElement (tri);
493 case TopAbs_VERTEX: { // VERTEX
494 // --------------------------
495 SMDS_NodeIteratorPtr nodeIt = smDS->GetNodes();
496 if ( nodeIt->more() )
497 ngNodeId( nodeIt->next(), ngMesh, nodeNgIdMap );
502 } // loop on submeshes
505 nodeVec.resize( ngMesh.GetNP() + 1 );
506 TNode2IdMap::iterator node_NgId, nodeNgIdEnd = nodeNgIdMap.end();
507 for ( node_NgId = nodeNgIdMap.begin(); node_NgId != nodeNgIdEnd; ++node_NgId)
508 nodeVec[ node_NgId->second ] = (SMDS_MeshNode*) node_NgId->first;
513 //=============================================================================
515 * Here we are going to use the NETGEN mesher
517 //=============================================================================
518 bool NETGENPlugin_Mesher::Compute()
521 netgen::MeshingParameters& mparams = netgen::GlobalMeshingParameters();
523 netgen::MeshingParameters& mparams = netgen::mparam;
525 MESSAGE("Compute with:\n"
526 " max size = " << mparams.maxh << "\n"
527 " segments per edge = " << mparams.segmentsperedge);
529 " growth rate = " << mparams.grading << "\n"
530 " elements per radius = " << mparams.curvaturesafety << "\n"
531 " second order = " << mparams.secondorder << "\n"
532 " quad allowed = " << mparams.quad);
534 SMESH_ComputeErrorPtr error = SMESH_ComputeError::New();
537 // -------------------------
538 // Prepare OCC geometry
539 // -------------------------
541 netgen::OCCGeometry occgeo;
542 list< SMESH_subMesh* > meshedSM;
543 PrepareOCCgeometry( occgeo, _shape, *_mesh, &meshedSM );
545 // -------------------------
547 // -------------------------
549 netgen::Mesh *ngMesh = NULL;
551 SMESH_Comment comment;
556 // vector of nodes in which node index == netgen ID
557 vector< SMDS_MeshNode* > nodeVec;
563 // pass 1D simple parameters to NETGEN
565 if ( int nbSeg = _simpleHyp->GetNumberOfSegments() ) {
567 mparams.segmentsperedge = nbSeg + 0.1;
568 mparams.maxh = occgeo.boundingbox.Diam();
569 mparams.grading = 0.01;
573 mparams.segmentsperedge = 1;
574 mparams.maxh = _simpleHyp->GetLocalLength();
577 // let netgen create ngMesh and calculate element size on not meshed shapes
579 int startWith = netgen::MESHCONST_ANALYSE;
580 int endWith = netgen::MESHCONST_ANALYSE;
581 err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
582 if (err) comment << "Error in netgen::OCCGenerateMesh() at MESHCONST_ANALYSE step";
584 // fill ngMesh with nodes and elements of computed submeshes
585 err = ! fillNgMesh(occgeo, *ngMesh, nodeVec, meshedSM);
586 nbInitNod = ngMesh->GetNP();
587 nbInitSeg = ngMesh->GetNSeg();
588 nbInitFac = ngMesh->GetNSE();
593 startWith = endWith = netgen::MESHCONST_MESHEDGES;
594 err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
595 if (err) comment << "Error in netgen::OCCGenerateMesh() at 1D mesh generation";
597 // ---------------------
598 // compute surface mesh
599 // ---------------------
602 // pass 2D simple parameters to NETGEN
604 if ( double area = _simpleHyp->GetMaxElementArea() ) {
606 mparams.maxh = sqrt(2. * area/sqrt(3.0));
607 mparams.grading = 0.4; // moderate size growth
612 for ( TopExp_Explorer exp( _shape, TopAbs_EDGE ); exp.More(); exp.Next() )
613 length += SMESH_Algo::EdgeLength( TopoDS::Edge( exp.Current() ));
614 if ( ngMesh->GetNSeg() )
615 mparams.maxh = length / ngMesh->GetNSeg();
618 mparams.grading = 0.2; // slow size growth
620 mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 );
621 ngMesh->SetGlobalH (mparams.maxh);
622 netgen::Box<3> bb = occgeo.GetBoundingBox();
623 bb.Increase (bb.Diam()/20);
624 ngMesh->SetLocalH (bb.PMin(), bb.PMax(), mparams.grading);
626 // let netgen compute 2D mesh
627 startWith = netgen::MESHCONST_MESHSURFACE;
628 endWith = _optimize ? netgen::MESHCONST_OPTSURFACE : netgen::MESHCONST_MESHSURFACE;
629 err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
630 if (err) comment << "Error in netgen::OCCGenerateMesh() at surface mesh generation";
632 // ---------------------
633 // generate volume mesh
634 // ---------------------
635 if (!err && _isVolume)
637 // add ng face descriptors of meshed faces
638 std::map< int, std::pair<int,int> >::iterator fId_soIds = _faceDescriptors.begin();
639 for ( ; fId_soIds != _faceDescriptors.end(); ++fId_soIds ) {
640 int faceID = fId_soIds->first;
641 int solidID1 = fId_soIds->second.first;
642 int solidID2 = fId_soIds->second.second;
643 ngMesh->AddFaceDescriptor (netgen::FaceDescriptor(faceID, solidID1, solidID2, 0));
645 // pass 3D simple parameters to NETGEN
646 const NETGENPlugin_SimpleHypothesis_3D* simple3d =
647 dynamic_cast< const NETGENPlugin_SimpleHypothesis_3D* > ( _simpleHyp );
649 if ( double vol = simple3d->GetMaxElementVolume() ) {
651 mparams.maxh = pow( 72, 1/6. ) * pow( vol, 1/3. );
652 mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 );
656 mparams.maxh = ngMesh->AverageH();
658 // netgen::ARRAY<double> maxhdom;
659 // maxhdom.SetSize (occgeo.NrSolids());
660 // maxhdom = mparams.maxh;
661 // ngMesh->SetMaxHDomain (maxhdom);
662 ngMesh->SetGlobalH (mparams.maxh);
663 mparams.grading = 0.4;
664 ngMesh->CalcLocalH();
666 // let netgen compute 3D mesh
667 startWith = netgen::MESHCONST_MESHVOLUME;
668 endWith = _optimize ? netgen::MESHCONST_OPTVOLUME : netgen::MESHCONST_MESHVOLUME;
669 err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
670 if (err) comment << "Error in netgen::OCCGenerateMesh()";
672 if (!err && mparams.secondorder > 0)
674 netgen::OCCRefinementSurfaces ref (occgeo);
675 ref.MakeSecondOrder (*ngMesh);
678 catch (netgen::NgException exc)
680 error->myName = err = COMPERR_ALGO_FAILED;
681 comment << exc.What();
684 int nbNod = ngMesh->GetNP();
685 int nbSeg = ngMesh->GetNSeg();
686 int nbFac = ngMesh->GetNSE();
687 int nbVol = ngMesh->GetNE();
689 MESSAGE((err ? "Mesh Generation failure" : "End of Mesh Generation") <<
690 ", nb nodes: " << nbNod <<
691 ", nb segments: " << nbSeg <<
692 ", nb faces: " << nbFac <<
693 ", nb volumes: " << nbVol);
695 // -----------------------------------------------------------
696 // Feed back the SMESHDS with the generated Nodes and Elements
697 // -----------------------------------------------------------
699 SMESHDS_Mesh* meshDS = _mesh->GetMeshDS();
700 bool isOK = ( !err && (_isVolume ? (nbVol > 0) : (nbFac > 0)) );
701 if ( true /*isOK*/ ) // get whatever built
703 // map of nodes assigned to submeshes
704 NCollection_Map<int> pindMap;
705 // create and insert nodes into nodeVec
706 nodeVec.resize( nbNod + 1 );
708 for (i = nbInitNod+1; i <= nbNod /*&& isOK*/; ++i )
710 const netgen::MeshPoint& ngPoint = ngMesh->Point(i);
711 SMDS_MeshNode* node = NULL;
712 bool newNodeOnVertex = false;
714 if (i-nbInitNod <= occgeo.vmap.Extent())
717 aVert = TopoDS::Vertex(occgeo.vmap(i-nbInitNod));
718 SMESHDS_SubMesh * submesh = meshDS->MeshElements(aVert);
721 SMDS_NodeIteratorPtr it = submesh->GetNodes();
724 node = const_cast<SMDS_MeshNode*> (it->next());
729 newNodeOnVertex = true;
732 node = meshDS->AddNode(ngPoint.X(), ngPoint.Y(), ngPoint.Z());
735 MESSAGE("Cannot create a mesh node");
736 if ( !comment.size() ) comment << "Cannot create a mesh node";
737 nbSeg = nbFac = nbVol = isOK = 0;
740 nodeVec.at(i) = node;
744 meshDS->SetNodeOnVertex(node, aVert);
749 // create mesh segments along geometric edges
750 NCollection_Map<Link> linkMap;
751 for (i = nbInitSeg+1; i <= nbSeg/* && isOK*/; ++i )
753 const netgen::Segment& seg = ngMesh->LineSegment(i);
754 Link link(seg.p1, seg.p2);
755 if (linkMap.Contains(link))
759 int pinds[3] = { seg.p1, seg.p2, seg.pmid };
762 for (int j=0; j < 3; ++j)
765 if (pind <= 0) continue;
772 int aGeomEdgeInd = seg.epgeominfo[j].edgenr;
773 if (aGeomEdgeInd > 0 && aGeomEdgeInd <= occgeo.emap.Extent())
774 aEdge = TopoDS::Edge(occgeo.emap(aGeomEdgeInd));
776 param = seg.epgeominfo[j].dist;
780 param = param2 * 0.5;
781 if (pind <= nbInitNod || pindMap.Contains(pind))
785 meshDS->SetNodeOnEdge(nodeVec.at(pind), aEdge, param);
790 if (nbp < 3) // second order ?
791 edge = meshDS->AddEdge(nodeVec.at(pinds[0]), nodeVec.at(pinds[1]));
793 edge = meshDS->AddEdge(nodeVec.at(pinds[0]), nodeVec.at(pinds[1]),
794 nodeVec.at(pinds[2]));
797 if ( !comment.size() ) comment << "Cannot create a mesh edge";
798 MESSAGE("Cannot create a mesh edge");
799 nbSeg = nbFac = nbVol = isOK = 0;
803 meshDS->SetMeshElementOnShape(edge, aEdge);
806 // create mesh faces along geometric faces
807 for (i = nbInitFac+1; i <= nbFac/* && isOK*/; ++i )
809 const netgen::Element2d& elem = ngMesh->SurfaceElement(i);
810 int aGeomFaceInd = elem.GetIndex();
812 if (aGeomFaceInd > 0 && aGeomFaceInd <= occgeo.fmap.Extent())
813 aFace = TopoDS::Face(occgeo.fmap(aGeomFaceInd));
814 vector<SMDS_MeshNode*> nodes;
815 for (int j=1; j <= elem.GetNP(); ++j)
817 int pind = elem.PNum(j);
818 SMDS_MeshNode* node = nodeVec.at(pind);
819 nodes.push_back(node);
820 if (pind <= nbInitNod || pindMap.Contains(pind))
824 const netgen::PointGeomInfo& pgi = elem.GeomInfoPi(j);
825 meshDS->SetNodeOnFace(node, aFace, pgi.u, pgi.v);
829 SMDS_MeshFace* face = NULL;
830 switch (elem.GetType())
833 face = meshDS->AddFace(nodes[0],nodes[1],nodes[2]);
836 face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[3]);
839 face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[5],nodes[3],nodes[4]);
842 face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[3],
843 nodes[4],nodes[7],nodes[5],nodes[6]);
846 MESSAGE("NETGEN created a face of unexpected type, ignoring");
851 if ( !comment.size() ) comment << "Cannot create a mesh face";
852 MESSAGE("Cannot create a mesh face");
853 nbSeg = nbFac = nbVol = isOK = 0;
857 meshDS->SetMeshElementOnShape(face, aFace);
861 for (i = 1; i <= nbVol/* && isOK*/; ++i)
863 const netgen::Element& elem = ngMesh->VolumeElement(i);
864 int aSolidInd = elem.GetIndex();
866 if (aSolidInd > 0 && aSolidInd <= occgeo.somap.Extent())
867 aSolid = TopoDS::Solid(occgeo.somap(aSolidInd));
868 vector<SMDS_MeshNode*> nodes;
869 for (int j=1; j <= elem.GetNP(); ++j)
871 int pind = elem.PNum(j);
872 SMDS_MeshNode* node = nodeVec.at(pind);
873 nodes.push_back(node);
874 if (pind <= nbInitNod || pindMap.Contains(pind))
876 if (!aSolid.IsNull())
879 meshDS->SetNodeInVolume(node, aSolid);
883 SMDS_MeshVolume* vol = NULL;
884 switch (elem.GetType())
887 vol = meshDS->AddVolume(nodes[0],nodes[1],nodes[2],nodes[3]);
890 vol = meshDS->AddVolume(nodes[0],nodes[1],nodes[2],nodes[3],
891 nodes[4],nodes[7],nodes[5],nodes[6],nodes[8],nodes[9]);
894 MESSAGE("NETGEN created a volume of unexpected type, ignoring");
899 if ( !comment.size() ) comment << "Cannot create a mesh volume";
900 MESSAGE("Cannot create a mesh volume");
901 nbSeg = nbFac = nbVol = isOK = 0;
904 if (!aSolid.IsNull())
905 meshDS->SetMeshElementOnShape(vol, aSolid);
909 if ( error->IsOK() && ( !isOK || comment.size() > 0 ))
910 error->myName = COMPERR_ALGO_FAILED;
911 if ( !comment.empty() )
912 error->myComment = comment;
914 // set bad compute error to subshapes of all failed subshapes shapes
915 if ( !error->IsOK() && err )
917 for (int i = 1; i <= occgeo.fmap.Extent(); i++) {
918 int status = occgeo.facemeshstatus[i-1];
919 if (status == 1 ) continue;
920 if ( SMESH_subMesh* sm = _mesh->GetSubMeshContaining( occgeo.fmap( i ))) {
921 SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
922 if ( !smError || smError->IsOK() ) {
924 smError.reset( new SMESH_ComputeError( error->myName, error->myComment ));
926 smError.reset( new SMESH_ComputeError( COMPERR_ALGO_FAILED, "Ignored" ));
932 nglib::Ng_DeleteMesh((nglib::Ng_Mesh*)ngMesh);
937 return error->IsOK();
940 //================================================================================
942 * \brief Remove "test.out" and "problemfaces" files in current directory
944 //================================================================================
946 void NETGENPlugin_Mesher::RemoveTmpFiles()
948 TCollection_AsciiString str("test.out");
949 OSD_Path path1( str );
950 OSD_File file1( path1 );
952 str = "problemfaces";
953 OSD_Path path2( str );
954 OSD_File file2( path2 );