1 // Copyright (C) 2005 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS, L3S, LJLL, MENSI
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License.
9 // This library is distributed in the hope that it will be useful
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 //=============================================================================
21 // File : NETGENPlugin_NETGEN_3D.cxx
22 // Moved here from SMESH_NETGEN_3D.cxx
23 // Created : lundi 27 Janvier 2003
24 // Author : Nadir BOUHAMOU (CEA)
26 // Copyright : CEA 2003
28 //=============================================================================
29 #include "NETGENPlugin_NETGEN_3D.hxx"
31 #include "NETGENPlugin_Mesher.hxx"
33 #include "SMDS_MeshElement.hxx"
34 #include "SMDS_MeshNode.hxx"
35 #include "SMESHDS_Mesh.hxx"
36 #include "SMESH_Comment.hxx"
37 #include "SMESH_ControlsDef.hxx"
38 #include "SMESH_Gen.hxx"
39 #include "SMESH_Mesh.hxx"
40 #include "SMESH_MesherHelper.hxx"
42 #include <BRep_Tool.hxx>
44 #include <TopExp_Explorer.hxx>
47 #include <Standard_Failure.hxx>
48 #include <Standard_ErrorHandler.hxx>
50 #include "utilities.h"
63 using namespace nglib;
65 //=============================================================================
69 //=============================================================================
71 NETGENPlugin_NETGEN_3D::NETGENPlugin_NETGEN_3D(int hypId, int studyId,
73 : SMESH_3D_Algo(hypId, studyId, gen)
75 MESSAGE("NETGENPlugin_NETGEN_3D::NETGENPlugin_NETGEN_3D");
77 _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);// 1 bit /shape type
78 _compatibleHypothesis.push_back("MaxElementVolume");
80 _maxElementVolume = 0.;
82 _hypMaxElementVolume = NULL;
85 //=============================================================================
89 //=============================================================================
91 NETGENPlugin_NETGEN_3D::~NETGENPlugin_NETGEN_3D()
93 MESSAGE("NETGENPlugin_NETGEN_3D::~NETGENPlugin_NETGEN_3D");
96 //=============================================================================
100 //=============================================================================
102 bool NETGENPlugin_NETGEN_3D::CheckHypothesis
104 const TopoDS_Shape& aShape,
105 SMESH_Hypothesis::Hypothesis_Status& aStatus)
107 MESSAGE("NETGENPlugin_NETGEN_3D::CheckHypothesis");
109 _hypMaxElementVolume = NULL;
110 _maxElementVolume = DBL_MAX;
112 list<const SMESHDS_Hypothesis*>::const_iterator itl;
113 const SMESHDS_Hypothesis* theHyp;
115 const list<const SMESHDS_Hypothesis*>& hyps = GetUsedHypothesis(aMesh, aShape);
116 int nbHyp = hyps.size();
119 aStatus = SMESH_Hypothesis::HYP_OK;
120 //aStatus = SMESH_Hypothesis::HYP_MISSING;
121 return true; // can work with no hypothesis
125 theHyp = (*itl); // use only the first hypothesis
127 string hypName = theHyp->GetName();
131 if (hypName == "MaxElementVolume")
133 _hypMaxElementVolume = static_cast<const StdMeshers_MaxElementVolume*> (theHyp);
134 ASSERT(_hypMaxElementVolume);
135 _maxElementVolume = _hypMaxElementVolume->GetMaxVolume();
137 aStatus = SMESH_Hypothesis::HYP_OK;
140 aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
145 //=============================================================================
147 *Here we are going to use the NETGEN mesher
149 //=============================================================================
151 bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh,
152 const TopoDS_Shape& aShape)
154 MESSAGE("NETGENPlugin_NETGEN_3D::Compute with maxElmentsize = " << _maxElementVolume);
156 SMESHDS_Mesh* meshDS = aMesh.GetMeshDS();
158 const int invalid_ID = -1;
160 SMESH::Controls::Area areaControl;
161 SMESH::Controls::TSequenceOfXYZ nodesCoords;
163 // -------------------------------------------------------------------
164 // get triangles on aShell and make a map of nodes to Netgen node IDs
165 // -------------------------------------------------------------------
167 SMESH_MesherHelper helper(aMesh);
168 SMESH_MesherHelper* myTool = &helper;
169 bool _quadraticMesh = myTool->IsQuadraticSubMesh(aShape);
171 typedef map< const SMDS_MeshNode*, int> TNodeToIDMap;
172 TNodeToIDMap nodeToNetgenID;
173 list< const SMDS_MeshElement* > triangles;
174 list< bool > isReversed; // orientation of triangles
176 // for the degeneraged edge: ignore all but one node on it;
177 // map storing ids of degen edges and vertices and their netgen id:
178 map< int, int* > degenShapeIdToPtrNgId;
179 map< int, int* >::iterator shId_ngId;
180 list< int > degenNgIds;
182 for (TopExp_Explorer exp(aShape,TopAbs_FACE);exp.More();exp.Next())
184 const TopoDS_Shape& aShapeFace = exp.Current();
185 const SMESHDS_SubMesh * aSubMeshDSFace = meshDS->MeshElements( aShapeFace );
186 if ( aSubMeshDSFace )
188 bool isRev = SMESH_Algo::IsReversedSubMesh( TopoDS::Face(aShapeFace), meshDS );
190 SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements();
191 while ( iteratorElem->more() ) // loop on elements on a face
194 const SMDS_MeshElement* elem = iteratorElem->next();
196 return error( COMPERR_BAD_INPUT_MESH, "Null element encounters");
197 bool isTraingle = ( elem->NbNodes()==3 || (_quadraticMesh && elem->NbNodes()==6 ));
199 return error( COMPERR_BAD_INPUT_MESH,
200 SMESH_Comment("Not triangle element ")<<elem->GetID());
202 triangles.push_back( elem );
203 isReversed.push_back( isRev );
204 // put elem nodes to nodeToNetgenID map
205 SMDS_ElemIteratorPtr triangleNodesIt = elem->nodesIterator();
206 while ( triangleNodesIt->more() ) {
207 const SMDS_MeshNode * node =
208 static_cast<const SMDS_MeshNode *>(triangleNodesIt->next());
209 if(myTool->IsMedium(node))
211 nodeToNetgenID.insert( make_pair( node, invalid_ID ));
214 // check if a trainge is degenerated
215 areaControl.GetPoints( elem, nodesCoords );
216 double area = areaControl.GetValue( nodesCoords );
217 if ( area <= DBL_MIN ) {
218 MESSAGE( "Warning: Degenerated " << elem );
222 // look for degeneraged edges and vetices
223 for (TopExp_Explorer expE(aShapeFace,TopAbs_EDGE);expE.More();expE.Next())
225 TopoDS_Edge aShapeEdge = TopoDS::Edge( expE.Current() );
226 if ( BRep_Tool::Degenerated( aShapeEdge ))
228 degenNgIds.push_back( invalid_ID );
229 int* ptrIdOnEdge = & degenNgIds.back();
231 int edgeID = meshDS->ShapeToIndex( aShapeEdge );
232 degenShapeIdToPtrNgId.insert( make_pair( edgeID, ptrIdOnEdge ));
233 // remember vertex id
234 int vertexID = meshDS->ShapeToIndex( TopExp::FirstVertex( aShapeEdge ));
235 degenShapeIdToPtrNgId.insert( make_pair( vertexID, ptrIdOnEdge ));
240 // ---------------------------------
241 // Feed the Netgen with surface mesh
242 // ---------------------------------
244 int Netgen_NbOfNodes = 0;
245 int Netgen_param2ndOrder = 0;
246 double Netgen_paramFine = 1.;
247 double Netgen_paramSize = _maxElementVolume;
249 double Netgen_point[3];
250 int Netgen_triangle[3];
251 int Netgen_tetrahedron[4];
255 Ng_Mesh * Netgen_mesh = Ng_NewMesh();
257 // set nodes and remember thier netgen IDs
258 bool isDegen = false, hasDegen = !degenShapeIdToPtrNgId.empty();
259 TNodeToIDMap::iterator n_id = nodeToNetgenID.begin();
260 for ( ; n_id != nodeToNetgenID.end(); ++n_id )
262 const SMDS_MeshNode* node = n_id->first;
264 // ignore nodes on degenerated edge
266 int shapeId = node->GetPosition()->GetShapeId();
267 shId_ngId = degenShapeIdToPtrNgId.find( shapeId );
268 isDegen = ( shId_ngId != degenShapeIdToPtrNgId.end() );
269 if ( isDegen && *(shId_ngId->second) != invalid_ID ) {
270 n_id->second = *(shId_ngId->second);
274 Netgen_point [ 0 ] = node->X();
275 Netgen_point [ 1 ] = node->Y();
276 Netgen_point [ 2 ] = node->Z();
277 Ng_AddPoint(Netgen_mesh, Netgen_point);
278 n_id->second = ++Netgen_NbOfNodes; // set netgen ID
280 if ( isDegen ) // all nodes on a degen edge get one netgen ID
281 *(shId_ngId->second) = n_id->second;
285 list< const SMDS_MeshElement* >::iterator tria = triangles.begin();
286 list< bool >::iterator reverse = isReversed.begin();
287 for ( ; tria != triangles.end(); ++tria, ++reverse )
290 SMDS_ElemIteratorPtr triangleNodesIt = (*tria)->nodesIterator();
291 while ( triangleNodesIt->more() ) {
292 const SMDS_MeshNode * node =
293 static_cast<const SMDS_MeshNode *>(triangleNodesIt->next());
294 if(myTool->IsMedium(node))
296 Netgen_triangle[ *reverse ? 2 - i : i ] = nodeToNetgenID[ node ];
300 // ignore degenerated triangles, they have 2 or 3 same ids
301 (Netgen_triangle[0] != Netgen_triangle[1] &&
302 Netgen_triangle[0] != Netgen_triangle[2] &&
303 Netgen_triangle[2] != Netgen_triangle[1] ))
304 Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle);
307 // -------------------------
308 // Generate the volume mesh
309 // -------------------------
311 Ng_Meshing_Parameters Netgen_param;
313 Netgen_param.secondorder = Netgen_param2ndOrder;
314 Netgen_param.fineness = Netgen_paramFine;
315 Netgen_param.maxh = Netgen_paramSize;
320 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
323 status = Ng_GenerateVolumeMesh(Netgen_mesh, &Netgen_param);
325 catch (Standard_Failure& exc) {
326 error(COMPERR_OCC_EXCEPTION, exc.GetMessageString());
327 status = NG_VOLUME_FAILURE;
330 error("Exception in Ng_GenerateVolumeMesh()");
331 status = NG_VOLUME_FAILURE;
333 if ( GetComputeError()->IsOK() ) {
335 case NG_SURFACE_INPUT_ERROR:error( status, "NG_SURFACE_INPUT_ERROR");
336 case NG_VOLUME_FAILURE: error( status, "NG_VOLUME_FAILURE");
337 case NG_STL_INPUT_ERROR: error( status, "NG_STL_INPUT_ERROR");
338 case NG_SURFACE_FAILURE: error( status, "NG_SURFACE_FAILURE");
339 case NG_FILE_NOT_FOUND: error( status, "NG_FILE_NOT_FOUND");
343 int Netgen_NbOfNodesNew = Ng_GetNP(Netgen_mesh);
345 int Netgen_NbOfTetra = Ng_GetNE(Netgen_mesh);
347 MESSAGE("End of Volume Mesh Generation. status=" << status <<
348 ", nb new nodes: " << Netgen_NbOfNodesNew - Netgen_NbOfNodes <<
349 ", nb tetra: " << Netgen_NbOfTetra);
351 // -------------------------------------------------------------------
352 // Feed back the SMESHDS with the generated Nodes and Volume Elements
353 // -------------------------------------------------------------------
355 bool isOK = ( /*status == NG_OK &&*/ Netgen_NbOfTetra > 0 );// get whatever built
358 // vector of nodes in which node index == netgen ID
359 vector< const SMDS_MeshNode* > nodeVec ( Netgen_NbOfNodesNew + 1 );
360 // insert old nodes into nodeVec
361 for ( n_id = nodeToNetgenID.begin(); n_id != nodeToNetgenID.end(); ++n_id ) {
362 nodeVec.at( n_id->second ) = n_id->first;
364 // create and insert new nodes into nodeVec
365 int nodeIndex = Netgen_NbOfNodes + 1;
366 int shapeID = meshDS->ShapeToIndex( aShape );
367 for ( ; nodeIndex <= Netgen_NbOfNodesNew; ++nodeIndex )
369 Ng_GetPoint( Netgen_mesh, nodeIndex, Netgen_point );
370 SMDS_MeshNode * node = meshDS->AddNode(Netgen_point[0],
373 meshDS->SetNodeInVolume(node, shapeID);
374 nodeVec.at(nodeIndex) = node;
377 // create tetrahedrons
378 for ( int elemIndex = 1; elemIndex <= Netgen_NbOfTetra; ++elemIndex )
380 Ng_GetVolumeElement(Netgen_mesh, elemIndex, Netgen_tetrahedron);
381 SMDS_MeshVolume * elt = myTool->AddVolume (nodeVec.at( Netgen_tetrahedron[0] ),
382 nodeVec.at( Netgen_tetrahedron[1] ),
383 nodeVec.at( Netgen_tetrahedron[2] ),
384 nodeVec.at( Netgen_tetrahedron[3] ));
385 meshDS->SetMeshElementOnShape(elt, shapeID );
389 Ng_DeleteMesh(Netgen_mesh);
392 NETGENPlugin_Mesher::RemoveTmpFiles();
394 return (status == NG_OK);
397 bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh,
398 SMESH_MesherHelper* aHelper)
400 MESSAGE("NETGENPlugin_NETGEN_3D::Compute with maxElmentsize = " << _maxElementVolume);
401 const int invalid_ID = -1;
402 bool _quadraticMesh = false;
403 typedef map< const SMDS_MeshNode*, int> TNodeToIDMap;
404 TNodeToIDMap nodeToNetgenID;
405 list< const SMDS_MeshElement* > triangles;
406 SMESHDS_Mesh* MeshDS = aHelper->GetMeshDS();
408 SMESH_MesherHelper::MType MeshType = aHelper->IsQuadraticMesh();
410 if(MeshType == SMESH_MesherHelper::COMP)
411 return error( COMPERR_BAD_INPUT_MESH,
412 SMESH_Comment("Mesh with linear and quadratic elements given."));
413 else if (MeshType == SMESH_MesherHelper::QUADRATIC)
414 _quadraticMesh = true;
416 SMDS_FaceIteratorPtr iteratorFace = MeshDS->facesIterator();
418 while(iteratorFace->more())
421 const SMDS_MeshElement* elem = iteratorFace->next();
423 return error( COMPERR_BAD_INPUT_MESH, "Null element encounters");
424 bool isTraingle = ( elem->NbNodes()==3 || (_quadraticMesh && elem->NbNodes()==6 ));
426 return error( COMPERR_BAD_INPUT_MESH,
427 SMESH_Comment("Not triangle element ")<<elem->GetID());
430 triangles.push_back( elem );
431 // put elem nodes to nodeToNetgenID map
432 SMDS_ElemIteratorPtr triangleNodesIt = elem->nodesIterator();
433 while ( triangleNodesIt->more() ) {
434 const SMDS_MeshNode * node =
435 static_cast<const SMDS_MeshNode *>(triangleNodesIt->next());
436 if(aHelper->IsMedium(node))
439 nodeToNetgenID.insert( make_pair( node, invalid_ID ));
443 // ---------------------------------
444 // Feed the Netgen with surface mesh
445 // ---------------------------------
447 int Netgen_NbOfNodes = 0;
448 int Netgen_param2ndOrder = 0;
449 double Netgen_paramFine = 1.;
450 double Netgen_paramSize = _maxElementVolume;
452 double Netgen_point[3];
453 int Netgen_triangle[3];
454 int Netgen_tetrahedron[4];
458 Ng_Mesh * Netgen_mesh = Ng_NewMesh();
460 // set nodes and remember thier netgen IDs
462 TNodeToIDMap::iterator n_id = nodeToNetgenID.begin();
463 for ( ; n_id != nodeToNetgenID.end(); ++n_id )
465 const SMDS_MeshNode* node = n_id->first;
467 Netgen_point [ 0 ] = node->X();
468 Netgen_point [ 1 ] = node->Y();
469 Netgen_point [ 2 ] = node->Z();
470 Ng_AddPoint(Netgen_mesh, Netgen_point);
471 n_id->second = ++Netgen_NbOfNodes; // set netgen ID
476 list< const SMDS_MeshElement* >::iterator tria = triangles.begin();
477 for ( ; tria != triangles.end(); ++tria)
480 SMDS_ElemIteratorPtr triangleNodesIt = (*tria)->nodesIterator();
481 while ( triangleNodesIt->more() ) {
482 const SMDS_MeshNode * node =
483 static_cast<const SMDS_MeshNode *>(triangleNodesIt->next());
484 if(aHelper->IsMedium(node))
486 Netgen_triangle[ i ] = nodeToNetgenID[ node ];
490 Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle);
493 // -------------------------
494 // Generate the volume mesh
495 // -------------------------
497 Ng_Meshing_Parameters Netgen_param;
499 Netgen_param.secondorder = Netgen_param2ndOrder;
500 Netgen_param.fineness = Netgen_paramFine;
501 Netgen_param.maxh = Netgen_paramSize;
506 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
509 status = Ng_GenerateVolumeMesh(Netgen_mesh, &Netgen_param);
511 catch (Standard_Failure& exc) {
512 error(COMPERR_OCC_EXCEPTION, exc.GetMessageString());
513 status = NG_VOLUME_FAILURE;
516 error("Bad mesh input!!!");
517 status = NG_VOLUME_FAILURE;
519 if ( GetComputeError()->IsOK() ) {
520 error( status, "Bad mesh input!!!");
523 int Netgen_NbOfNodesNew = Ng_GetNP(Netgen_mesh);
525 int Netgen_NbOfTetra = Ng_GetNE(Netgen_mesh);
527 MESSAGE("End of Volume Mesh Generation. status=" << status <<
528 ", nb new nodes: " << Netgen_NbOfNodesNew - Netgen_NbOfNodes <<
529 ", nb tetra: " << Netgen_NbOfTetra);
531 // -------------------------------------------------------------------
532 // Feed back the SMESHDS with the generated Nodes and Volume Elements
533 // -------------------------------------------------------------------
535 bool isOK = ( Netgen_NbOfTetra > 0 );// get whatever built
538 // vector of nodes in which node index == netgen ID
539 vector< const SMDS_MeshNode* > nodeVec ( Netgen_NbOfNodesNew + 1 );
540 // insert old nodes into nodeVec
541 for ( n_id = nodeToNetgenID.begin(); n_id != nodeToNetgenID.end(); ++n_id ) {
542 nodeVec.at( n_id->second ) = n_id->first;
544 // create and insert new nodes into nodeVec
545 int nodeIndex = Netgen_NbOfNodes + 1;
547 for ( ; nodeIndex <= Netgen_NbOfNodesNew; ++nodeIndex )
549 Ng_GetPoint( Netgen_mesh, nodeIndex, Netgen_point );
550 SMDS_MeshNode * node = aHelper->AddNode(Netgen_point[0],
553 nodeVec.at(nodeIndex) = node;
556 // create tetrahedrons
557 for ( int elemIndex = 1; elemIndex <= Netgen_NbOfTetra; ++elemIndex )
559 Ng_GetVolumeElement(Netgen_mesh, elemIndex, Netgen_tetrahedron);
560 aHelper->AddVolume (nodeVec.at( Netgen_tetrahedron[0] ),
561 nodeVec.at( Netgen_tetrahedron[1] ),
562 nodeVec.at( Netgen_tetrahedron[2] ),
563 nodeVec.at( Netgen_tetrahedron[3] ));
567 Ng_DeleteMesh(Netgen_mesh);
570 NETGENPlugin_Mesher::RemoveTmpFiles();
572 return (status == NG_OK);