]> SALOME platform Git repositories - plugins/netgenplugin.git/blob - src/NETGENPlugin/NETGENPlugin_NETGEN_3D.cxx
Salome HOME
Merge from V5_1_4_BR 07/05/2010
[plugins/netgenplugin.git] / src / NETGENPlugin / NETGENPlugin_NETGEN_3D.cxx
1 //  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
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.
10 //
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.
15 //
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
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //=============================================================================
24 // File      : NETGENPlugin_NETGEN_3D.cxx
25 //             Moved here from SMESH_NETGEN_3D.cxx
26 // Created   : lundi 27 Janvier 2003
27 // Author    : Nadir BOUHAMOU (CEA)
28 // Project   : SALOME
29 //=============================================================================
30 //
31 #include "NETGENPlugin_NETGEN_3D.hxx"
32
33 #include "NETGENPlugin_Mesher.hxx"
34
35 #include "SMDS_MeshElement.hxx"
36 #include "SMDS_MeshNode.hxx"
37 #include "SMESHDS_Mesh.hxx"
38 #include "SMESH_Comment.hxx"
39 #include "SMESH_ControlsDef.hxx"
40 #include "SMESH_Gen.hxx"
41 #include "SMESH_Mesh.hxx"
42 #include "SMESH_MesherHelper.hxx"
43 #include "SMESH_MeshEditor.hxx"
44 #include "StdMeshers_QuadToTriaAdaptor.hxx"
45
46 #include <BRepGProp.hxx>
47 #include <BRep_Tool.hxx>
48 #include <GProp_GProps.hxx>
49 #include <TopExp.hxx>
50 #include <TopExp_Explorer.hxx>
51 #include <TopTools_ListIteratorOfListOfShape.hxx>
52 #include <TopoDS.hxx>
53
54 #include <Standard_Failure.hxx>
55 #include <Standard_ErrorHandler.hxx>
56
57 #include "utilities.h"
58
59 #include <list>
60 #include <vector>
61 #include <map>
62
63 /*
64   Netgen include files
65 */
66
67 #define OCCGEOMETRY
68 #include <occgeom.hpp>
69 namespace nglib {
70 #include <nglib.h>
71 }
72 using namespace nglib;
73 using namespace std;
74
75 //=============================================================================
76 /*!
77  *  
78  */
79 //=============================================================================
80
81 NETGENPlugin_NETGEN_3D::NETGENPlugin_NETGEN_3D(int hypId, int studyId,
82                              SMESH_Gen* gen)
83   : SMESH_3D_Algo(hypId, studyId, gen)
84 {
85   MESSAGE("NETGENPlugin_NETGEN_3D::NETGENPlugin_NETGEN_3D");
86   _name = "NETGEN_3D";
87   _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);// 1 bit /shape type
88   _compatibleHypothesis.push_back("MaxElementVolume");
89
90   _maxElementVolume = 0.;
91
92   _hypMaxElementVolume = NULL;
93
94   _requireShape = false; // can work without shape
95 }
96
97 //=============================================================================
98 /*!
99  *  
100  */
101 //=============================================================================
102
103 NETGENPlugin_NETGEN_3D::~NETGENPlugin_NETGEN_3D()
104 {
105   MESSAGE("NETGENPlugin_NETGEN_3D::~NETGENPlugin_NETGEN_3D");
106 }
107
108 //=============================================================================
109 /*!
110  *  
111  */
112 //=============================================================================
113
114 bool NETGENPlugin_NETGEN_3D::CheckHypothesis (SMESH_Mesh&         aMesh,
115                                               const TopoDS_Shape& aShape,
116                                               Hypothesis_Status&  aStatus)
117 {
118   MESSAGE("NETGENPlugin_NETGEN_3D::CheckHypothesis");
119
120   _hypMaxElementVolume = NULL;
121   _maxElementVolume = DBL_MAX;
122
123   list<const SMESHDS_Hypothesis*>::const_iterator itl;
124   const SMESHDS_Hypothesis* theHyp;
125
126   const list<const SMESHDS_Hypothesis*>& hyps = GetUsedHypothesis(aMesh, aShape);
127   int nbHyp = hyps.size();
128   if (!nbHyp)
129   {
130     aStatus = SMESH_Hypothesis::HYP_OK;
131     //aStatus = SMESH_Hypothesis::HYP_MISSING;
132     return true;  // can work with no hypothesis
133   }
134
135   itl = hyps.begin();
136   theHyp = (*itl); // use only the first hypothesis
137
138   string hypName = theHyp->GetName();
139
140   bool isOk = false;
141
142   if (hypName == "MaxElementVolume")
143   {
144     _hypMaxElementVolume = static_cast<const StdMeshers_MaxElementVolume*> (theHyp);
145     ASSERT(_hypMaxElementVolume);
146     _maxElementVolume = _hypMaxElementVolume->GetMaxVolume();
147     isOk =true;
148     aStatus = SMESH_Hypothesis::HYP_OK;
149   }
150   else
151     aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
152
153   return isOk;
154 }
155
156 //=============================================================================
157 /*!
158  *Here we are going to use the NETGEN mesher
159  */
160 //=============================================================================
161
162 bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh&         aMesh,
163                                      const TopoDS_Shape& aShape)
164 {
165   MESSAGE("NETGENPlugin_NETGEN_3D::Compute with maxElmentsize = " << _maxElementVolume);
166
167   SMESHDS_Mesh* meshDS = aMesh.GetMeshDS();
168
169   SMESH_MesherHelper helper(aMesh);
170   bool _quadraticMesh = helper.IsQuadraticSubMesh(aShape);
171   helper.SetElementsOnShape( true );
172
173   int Netgen_NbOfNodes     = 0;
174   int Netgen_param2ndOrder = 0;
175   double Netgen_paramFine  = 1.;
176   double Netgen_paramSize  = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. );
177
178   double Netgen_point[3];
179   int Netgen_triangle[3];
180   int Netgen_tetrahedron[4];
181
182   NETGENPlugin_NetgenLibWrapper ngLib;
183   Ng_Mesh * Netgen_mesh = ngLib._ngMesh;
184
185   // vector of nodes in which node index == netgen ID
186   vector< const SMDS_MeshNode* > nodeVec;
187   {
188     const int invalid_ID = -1;
189
190     SMESH::Controls::Area areaControl;
191     SMESH::Controls::TSequenceOfXYZ nodesCoords;
192
193     // maps nodes to ng ID
194     typedef map< const SMDS_MeshNode*, int, TIDCompare > TNodeToIDMap;
195     typedef TNodeToIDMap::value_type                     TN2ID;
196     TNodeToIDMap nodeToNetgenID;
197
198     // find internal shapes
199     NETGENPlugin_Internals internals( aMesh, aShape, /*is3D=*/true );
200
201     // ---------------------------------
202     // Feed the Netgen with surface mesh
203     // ---------------------------------
204
205     TopAbs_ShapeEnum mainType = aMesh.GetShapeToMesh().ShapeType();
206     bool checkReverse = ( mainType == TopAbs_COMPOUND || mainType == TopAbs_COMPSOLID );
207
208     StdMeshers_QuadToTriaAdaptor Adaptor;
209     if ( aMesh.NbQuadrangles() > 0 )
210       Adaptor.Compute(aMesh,aShape);
211
212     for ( TopExp_Explorer exFa( aShape, TopAbs_FACE ); exFa.More(); exFa.Next())
213     {
214       const TopoDS_Shape& aShapeFace = exFa.Current();
215       int faceID = meshDS->ShapeToIndex( aShapeFace );
216       bool isInternalFace = internals.isInternalShape( faceID );
217       bool isRev = false;
218       if ( checkReverse && !isInternalFace &&
219            helper.NbAncestors(aShapeFace, aMesh, aShape.ShapeType()) > 1 )
220         // IsReversedSubMesh() can work wrong on strongly curved faces,
221         // so we use it as less as possible
222         isRev = SMESH_Algo::IsReversedSubMesh( TopoDS::Face(aShapeFace), meshDS );
223
224       const SMESHDS_SubMesh * aSubMeshDSFace = meshDS->MeshElements( aShapeFace );
225       if ( !aSubMeshDSFace ) continue;
226       SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements();
227       while ( iteratorElem->more() ) // loop on elements on a geom face
228       {
229         // check mesh face
230         const SMDS_MeshElement* elem = iteratorElem->next();
231         if ( !elem )
232           return error( COMPERR_BAD_INPUT_MESH, "Null element encounters");
233         vector< const SMDS_MeshElement* > trias;
234         bool isTraingle = ( elem->NbNodes() == ( elem->IsQuadratic() ? 6 : 3 ));
235         if ( !isTraingle )
236         {
237           // use adaptor to convert quadrangle face into triangles
238           const list<const SMDS_FaceOfNodes*>* faces = Adaptor.GetTriangles(elem);
239           if(faces==0)
240             return error( COMPERR_BAD_INPUT_MESH,
241                           SMESH_Comment("No triangles in adaptor for element ")<<elem->GetID());
242           trias.assign( faces->begin(), faces->end() );
243         }
244         else
245         {
246           trias.push_back( elem );
247         }
248         // Add nodes of triangles and triangles them-selves to netgen mesh
249
250         for ( int i = 0; i < trias.size(); ++i )
251         {
252           // add three nodes of triangle
253           bool hasDegen = false;
254           for ( int iN = 0; iN < 3; ++iN )
255           {
256             const SMDS_MeshNode* node = trias[i]->GetNode( iN );
257             int shapeID = node->GetPosition()->GetShapeId();
258             if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_EDGE &&
259                  helper.IsDegenShape( shapeID ))
260             {
261               // ignore all nodes on degeneraged edge and use node on its vertex instead
262               TopoDS_Shape vertex = TopoDS_Iterator( meshDS->IndexToShape( shapeID )).Value();
263               node = SMESH_Algo::VertexNode( TopoDS::Vertex( vertex ), meshDS );
264               hasDegen = true;
265             }
266             int& ngID = nodeToNetgenID.insert(TN2ID( node, invalid_ID )).first->second;
267             if ( ngID == invalid_ID )
268             {
269               ngID = ++Netgen_NbOfNodes;
270               Netgen_point [ 0 ] = node->X();
271               Netgen_point [ 1 ] = node->Y();
272               Netgen_point [ 2 ] = node->Z();
273               Ng_AddPoint(Netgen_mesh, Netgen_point);
274             }
275             Netgen_triangle[ isRev ? 2-iN : iN ] = ngID;
276           }
277           // add triangle
278           if ( hasDegen && (Netgen_triangle[0] == Netgen_triangle[1] ||
279                             Netgen_triangle[0] == Netgen_triangle[2] ||
280                             Netgen_triangle[2] == Netgen_triangle[1] ))
281             continue;
282
283           Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle);
284
285           if ( isInternalFace && isTraingle )
286           {
287             swap( Netgen_triangle[1], Netgen_triangle[2] );
288             Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle);
289           }
290         }
291 #ifdef _DEBUG_
292         // check if a trainge is degenerated
293         areaControl.GetPoints( elem, nodesCoords );
294         double area = areaControl.GetValue( nodesCoords );
295         if ( area <= DBL_MIN ) {
296           MESSAGE( "Warning: Degenerated " << elem );
297         }
298 #endif
299       } // loop on elements on a face
300     } // loop on faces of a SOLID or SHELL
301
302     // insert old nodes into nodeVec
303     nodeVec.resize( nodeToNetgenID.size() + 1, 0 );
304     TNodeToIDMap::iterator n_id = nodeToNetgenID.begin();
305     for ( ; n_id != nodeToNetgenID.end(); ++n_id )
306       nodeVec[ n_id->second ] = n_id->first;
307     nodeToNetgenID.clear();
308
309     if ( internals.hasInternalVertexInSolid() )
310     {
311       netgen::OCCGeometry occgeo;
312       NETGENPlugin_Mesher::addIntVerticesInSolids( occgeo,
313                                                    (netgen::Mesh&) *Netgen_mesh,
314                                                    nodeVec,
315                                                    internals);
316       Netgen_NbOfNodes = Ng_GetNP(Netgen_mesh);
317     }
318   }
319
320   // -------------------------
321   // Generate the volume mesh
322   // -------------------------
323
324   Ng_Meshing_Parameters Netgen_param;
325
326   Netgen_param.secondorder = Netgen_param2ndOrder;
327   Netgen_param.fineness    = Netgen_paramFine;
328   Netgen_param.maxh        = Netgen_paramSize;
329
330   Ng_Result status;
331
332   try {
333 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
334     OCC_CATCH_SIGNALS;
335 #endif
336     status = Ng_GenerateVolumeMesh(Netgen_mesh, &Netgen_param);
337   }
338   catch (Standard_Failure& exc) {
339     error(COMPERR_OCC_EXCEPTION, exc.GetMessageString());
340     status = NG_VOLUME_FAILURE;
341   }
342   catch (...) {
343     error("Exception in Ng_GenerateVolumeMesh()");
344     status = NG_VOLUME_FAILURE;
345   }
346   if ( GetComputeError()->IsOK() ) {
347     switch ( status ) {
348     case NG_SURFACE_INPUT_ERROR:error( status, "NG_SURFACE_INPUT_ERROR");
349     case NG_VOLUME_FAILURE:     error( status, "NG_VOLUME_FAILURE");
350     case NG_STL_INPUT_ERROR:    error( status, "NG_STL_INPUT_ERROR");
351     case NG_SURFACE_FAILURE:    error( status, "NG_SURFACE_FAILURE");
352     case NG_FILE_NOT_FOUND:     error( status, "NG_FILE_NOT_FOUND");
353     };
354   }
355
356   int Netgen_NbOfNodesNew = Ng_GetNP(Netgen_mesh);
357   int Netgen_NbOfTetra    = Ng_GetNE(Netgen_mesh);
358
359   MESSAGE("End of Volume Mesh Generation. status=" << status <<
360           ", nb new nodes: " << Netgen_NbOfNodesNew - Netgen_NbOfNodes <<
361           ", nb tetra: " << Netgen_NbOfTetra);
362
363   // -------------------------------------------------------------------
364   // Feed back the SMESHDS with the generated Nodes and Volume Elements
365   // -------------------------------------------------------------------
366
367   if ( status == NG_VOLUME_FAILURE )
368   {
369     SMESH_ComputeErrorPtr err = NETGENPlugin_Mesher::readErrors(nodeVec);
370     if ( err && !err->myBadElements.empty() )
371       error( err );
372   }
373
374   bool isOK = ( /*status == NG_OK &&*/ Netgen_NbOfTetra > 0 );// get whatever built
375   if ( isOK )
376   {
377     // create and insert new nodes into nodeVec
378     nodeVec.resize( Netgen_NbOfNodesNew + 1, 0 );
379     int nodeIndex = Netgen_NbOfNodes + 1;
380     for ( ; nodeIndex <= Netgen_NbOfNodesNew; ++nodeIndex )
381     {
382       Ng_GetPoint( Netgen_mesh, nodeIndex, Netgen_point );
383       nodeVec.at(nodeIndex) = helper.AddNode(Netgen_point[0], Netgen_point[1], Netgen_point[2]);
384     }
385
386     // create tetrahedrons
387     for ( int elemIndex = 1; elemIndex <= Netgen_NbOfTetra; ++elemIndex )
388     {
389       Ng_GetVolumeElement(Netgen_mesh, elemIndex, Netgen_tetrahedron);
390       helper.AddVolume (nodeVec.at( Netgen_tetrahedron[0] ),
391                         nodeVec.at( Netgen_tetrahedron[1] ),
392                         nodeVec.at( Netgen_tetrahedron[2] ),
393                         nodeVec.at( Netgen_tetrahedron[3] ));
394     }
395   }
396
397   return (status == NG_OK);
398 }
399
400 //================================================================================
401 /*!
402  * \brief Compute tetrahedral mesh from 2D mesh without geometry
403  */
404 //================================================================================
405
406 bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh&         aMesh,
407                                      SMESH_MesherHelper* aHelper)
408 {
409   MESSAGE("NETGENPlugin_NETGEN_3D::Compute with maxElmentsize = " << _maxElementVolume);  
410   const int invalid_ID = -1;
411   bool _quadraticMesh = false;
412   typedef map< const SMDS_MeshNode*, int, TIDCompare > TNodeToIDMap;
413   TNodeToIDMap nodeToNetgenID;
414   list< const SMDS_MeshElement* > triangles;
415   SMESHDS_Mesh* MeshDS = aHelper->GetMeshDS();
416
417   SMESH_MesherHelper::MType MeshType = aHelper->IsQuadraticMesh();
418   
419   if(MeshType == SMESH_MesherHelper::COMP)
420     return error( COMPERR_BAD_INPUT_MESH,
421                   SMESH_Comment("Mesh with linear and quadratic elements given."));
422   else if (MeshType == SMESH_MesherHelper::QUADRATIC)
423     _quadraticMesh = true;
424     
425   StdMeshers_QuadToTriaAdaptor Adaptor;
426   Adaptor.Compute(aMesh);
427
428   SMDS_FaceIteratorPtr fIt = MeshDS->facesIterator();
429   TIDSortedElemSet sortedFaces; //  0020279: control the "random" use when using mesh algorithms
430   while( fIt->more()) sortedFaces.insert( fIt->next() );
431
432   TIDSortedElemSet::iterator itFace = sortedFaces.begin(), fEnd = sortedFaces.end();
433   for ( ; itFace != fEnd; ++itFace )
434   {
435     // check element
436     const SMDS_MeshElement* elem = *itFace;
437     if ( !elem )
438       return error( COMPERR_BAD_INPUT_MESH, "Null element encounters");
439
440     vector< const SMDS_MeshElement* > trias;
441     bool isTraingle = ( elem->NbNodes() == ( elem->IsQuadratic() ? 6 : 3 ));
442     if ( !isTraingle ) {
443       // using adaptor
444       const list<const SMDS_FaceOfNodes*>* faces = Adaptor.GetTriangles(elem);
445       if(faces==0)
446         continue; // Issue 0020682. There already can be 3d mesh
447       trias.assign( faces->begin(), faces->end() );
448     }
449     else {
450       trias.push_back( elem );
451     }
452     for ( int i = 0; i < trias.size(); ++i )
453     {
454       triangles.push_back( trias[i] );
455       for ( int iN = 0; iN < 3; ++iN )
456       {
457         const SMDS_MeshNode* node = trias[i]->GetNode( iN );
458         // put elem nodes to nodeToNetgenID map
459         nodeToNetgenID.insert( make_pair( node, invalid_ID ));
460       }
461     }
462   }
463
464   // ---------------------------------
465   // Feed the Netgen with surface mesh
466   // ---------------------------------
467
468   int Netgen_NbOfNodes = 0;
469   int Netgen_param2ndOrder = 0;
470   double Netgen_paramFine = 1.;
471   double Netgen_paramSize = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. );
472   
473   double Netgen_point[3];
474   int Netgen_triangle[3];
475   int Netgen_tetrahedron[4];
476
477   NETGENPlugin_NetgenLibWrapper ngLib;
478   Ng_Mesh * Netgen_mesh = ngLib._ngMesh;
479
480   // set nodes and remember thier netgen IDs
481   
482   TNodeToIDMap::iterator n_id = nodeToNetgenID.begin();
483   for ( ; n_id != nodeToNetgenID.end(); ++n_id )
484   {
485     const SMDS_MeshNode* node = n_id->first;
486
487     Netgen_point [ 0 ] = node->X();
488     Netgen_point [ 1 ] = node->Y();
489     Netgen_point [ 2 ] = node->Z();
490     Ng_AddPoint(Netgen_mesh, Netgen_point);
491     n_id->second = ++Netgen_NbOfNodes; // set netgen ID
492   }
493
494   // set triangles
495   list< const SMDS_MeshElement* >::iterator tria = triangles.begin();
496   for ( ; tria != triangles.end(); ++tria)
497   {
498     int i = 0;
499     SMDS_ElemIteratorPtr triangleNodesIt = (*tria)->nodesIterator();
500     while ( triangleNodesIt->more() ) {
501       const SMDS_MeshNode * node =
502         static_cast<const SMDS_MeshNode *>(triangleNodesIt->next());
503       if(aHelper->IsMedium(node))
504         continue;
505       Netgen_triangle[ i ] = nodeToNetgenID[ node ];
506       ++i;
507     }
508     Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle);
509   }
510
511   // -------------------------
512   // Generate the volume mesh
513   // -------------------------
514
515   Ng_Meshing_Parameters Netgen_param;
516
517   Netgen_param.secondorder = Netgen_param2ndOrder;
518   Netgen_param.fineness = Netgen_paramFine;
519   Netgen_param.maxh = Netgen_paramSize;
520
521   Ng_Result status;
522
523   try {
524 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
525     OCC_CATCH_SIGNALS;
526 #endif
527     status = Ng_GenerateVolumeMesh(Netgen_mesh, &Netgen_param);
528   }
529   catch (Standard_Failure& exc) {
530     error(COMPERR_OCC_EXCEPTION, exc.GetMessageString());
531     status = NG_VOLUME_FAILURE;
532   }
533   catch (...) {
534     error("Bad mesh input!!!");
535     status = NG_VOLUME_FAILURE;
536   }
537   if ( GetComputeError()->IsOK() ) {
538     error( status, "Bad mesh input!!!");
539   }
540
541   int Netgen_NbOfNodesNew = Ng_GetNP(Netgen_mesh);
542
543   int Netgen_NbOfTetra = Ng_GetNE(Netgen_mesh);
544
545   MESSAGE("End of Volume Mesh Generation. status=" << status <<
546           ", nb new nodes: " << Netgen_NbOfNodesNew - Netgen_NbOfNodes <<
547           ", nb tetra: " << Netgen_NbOfTetra);
548
549   // -------------------------------------------------------------------
550   // Feed back the SMESHDS with the generated Nodes and Volume Elements
551   // -------------------------------------------------------------------
552
553   bool isOK = ( Netgen_NbOfTetra > 0 );// get whatever built
554   if ( isOK )
555   {
556     // vector of nodes in which node index == netgen ID
557     vector< const SMDS_MeshNode* > nodeVec ( Netgen_NbOfNodesNew + 1 );
558     // insert old nodes into nodeVec
559     for ( n_id = nodeToNetgenID.begin(); n_id != nodeToNetgenID.end(); ++n_id ) {
560       nodeVec.at( n_id->second ) = n_id->first;
561     }
562     // create and insert new nodes into nodeVec
563     int nodeIndex = Netgen_NbOfNodes + 1;
564     
565     for ( ; nodeIndex <= Netgen_NbOfNodesNew; ++nodeIndex )
566     {
567       Ng_GetPoint( Netgen_mesh, nodeIndex, Netgen_point );
568       SMDS_MeshNode * node = aHelper->AddNode(Netgen_point[0],
569                                               Netgen_point[1],
570                                               Netgen_point[2]);
571       nodeVec.at(nodeIndex) = node;
572     }
573
574     // create tetrahedrons
575     for ( int elemIndex = 1; elemIndex <= Netgen_NbOfTetra; ++elemIndex )
576     {
577       Ng_GetVolumeElement(Netgen_mesh, elemIndex, Netgen_tetrahedron);
578       aHelper->AddVolume (nodeVec.at( Netgen_tetrahedron[0] ),
579                           nodeVec.at( Netgen_tetrahedron[1] ),
580                           nodeVec.at( Netgen_tetrahedron[2] ),
581                           nodeVec.at( Netgen_tetrahedron[3] ));
582     }
583   }
584
585   return (status == NG_OK);
586 }
587
588
589 //=============================================================================
590 /*!
591  *
592  */
593 //=============================================================================
594
595 bool NETGENPlugin_NETGEN_3D::Evaluate(SMESH_Mesh& aMesh,
596                                       const TopoDS_Shape& aShape,
597                                       MapShapeNbElems& aResMap)
598 {
599   int nbtri = 0, nbqua = 0;
600   double fullArea = 0.0;
601   for (TopExp_Explorer expF(aShape, TopAbs_FACE); expF.More(); expF.Next()) {
602     TopoDS_Face F = TopoDS::Face( expF.Current() );
603     SMESH_subMesh *sm = aMesh.GetSubMesh(F);
604     MapShapeNbElemsItr anIt = aResMap.find(sm);
605     if( anIt==aResMap.end() ) {
606       SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
607       smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this));
608       return false;
609     }
610     std::vector<int> aVec = (*anIt).second;
611     nbtri += Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]);
612     nbqua += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
613     GProp_GProps G;
614     BRepGProp::SurfaceProperties(F,G);
615     double anArea = G.Mass();
616     fullArea += anArea;
617   }
618
619   // collect info from edges
620   int nb0d_e = 0, nb1d_e = 0;
621   bool IsQuadratic = false;
622   bool IsFirst = true;
623   TopTools_MapOfShape tmpMap;
624   for (TopExp_Explorer expF(aShape, TopAbs_EDGE); expF.More(); expF.Next()) {
625     TopoDS_Edge E = TopoDS::Edge(expF.Current());
626     if( tmpMap.Contains(E) )
627       continue;
628     tmpMap.Add(E);
629     SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(expF.Current());
630     MapShapeNbElemsItr anIt = aResMap.find(aSubMesh);
631     if( anIt==aResMap.end() ) {
632       SMESH_ComputeErrorPtr& smError = aSubMesh->GetComputeError();
633       smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,
634                                             "Submesh can not be evaluated",this));
635       return false;
636     }
637     std::vector<int> aVec = (*anIt).second;
638     nb0d_e += aVec[SMDSEntity_Node];
639     nb1d_e += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
640     if(IsFirst) {
641       IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]);
642       IsFirst = false;
643     }
644   }
645   tmpMap.Clear();
646
647   double ELen_face = sqrt(2.* ( fullArea/(nbtri+nbqua*2) ) / sqrt(3.0) );
648   double ELen_vol = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. );
649   double ELen = Min(ELen_vol,ELen_face*2);
650
651   GProp_GProps G;
652   BRepGProp::VolumeProperties(aShape,G);
653   double aVolume = G.Mass();
654   double tetrVol = 0.1179*ELen*ELen*ELen;
655   double CoeffQuality = 0.9;
656   int nbVols = int( aVolume/tetrVol/CoeffQuality );
657   int nb1d_f = (nbtri*3 + nbqua*4 - nb1d_e) / 2;
658   int nb1d_in = (nbVols*6 - nb1d_e - nb1d_f ) / 5;
659   std::vector<int> aVec(SMDSEntity_Last);
660   for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i]=0;
661   if( IsQuadratic ) {
662     aVec[SMDSEntity_Node] = nb1d_in/6 + 1 + nb1d_in;
663     aVec[SMDSEntity_Quad_Tetra] = nbVols - nbqua*2;
664     aVec[SMDSEntity_Quad_Pyramid] = nbqua;
665   }
666   else {
667     aVec[SMDSEntity_Node] = nb1d_in/6 + 1;
668     aVec[SMDSEntity_Tetra] = nbVols - nbqua*2;
669     aVec[SMDSEntity_Pyramid] = nbqua;
670   }
671   SMESH_subMesh *sm = aMesh.GetSubMesh(aShape);
672   aResMap.insert(std::make_pair(sm,aVec));
673   
674   return true;
675 }