Salome HOME
Synchronize adm files
[plugins/netgenplugin.git] / src / NETGENPlugin / NETGENPlugin_Mesher.cxx
old mode 100644 (file)
new mode 100755 (executable)
index 63f6c3c..a533654
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -6,7 +6,7 @@
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 // License as published by the Free Software Foundation; either
-// version 2.1 of the License.
+// version 2.1 of the License, or (at your option) any later version.
 //
 // This library is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -83,11 +83,15 @@ namespace netgen {
   //extern void OCCSetLocalMeshSize(OCCGeometry & geom, Mesh & mesh);
   extern MeshingParameters mparam;
   extern volatile multithreadt multithread;
+  extern bool merge_solids;
 }
 
 #include <vector>
 #include <limits>
 
+#ifdef WIN32
+#include <process.h>
+#endif
 using namespace nglib;
 using namespace std;
 
@@ -124,7 +128,13 @@ NETGENPlugin_Mesher::NETGENPlugin_Mesher (SMESH_Mesh*         mesh,
     _optimize(true),
     _fineness(NETGENPlugin_Hypothesis::GetDefaultFineness()),
     _isViscousLayers2D(false),
-    _simpleHyp(NULL)
+    _ngMesh(NULL),
+    _occgeom(NULL),
+    _curShapeIndex(-1),
+    _progressTic(1),
+    _totalTime(1.0),
+    _simpleHyp(NULL),
+    _ptrToMe(NULL)
 {
   SetDefaultParameters();
   ShapesWithLocalSize.Clear();
@@ -133,6 +143,38 @@ NETGENPlugin_Mesher::NETGENPlugin_Mesher (SMESH_Mesh*         mesh,
   FaceId2LocalSize.clear();
 }
 
+//================================================================================
+/*!
+ * Destuctor
+ */
+//================================================================================
+
+NETGENPlugin_Mesher::~NETGENPlugin_Mesher()
+{
+  if ( _ptrToMe )
+    *_ptrToMe = NULL;
+  _ptrToMe = 0;
+  _ngMesh = NULL;
+}
+
+//================================================================================
+/*!
+ * Set pointer to NETGENPlugin_Mesher* field of the holder, that will be
+ * nullified at destruction of this
+ */
+//================================================================================
+
+void NETGENPlugin_Mesher::SetSelfPointer( NETGENPlugin_Mesher ** ptr )
+{
+  if ( _ptrToMe )
+    *_ptrToMe = NULL;
+
+  _ptrToMe = ptr;
+
+  if ( _ptrToMe )
+    *_ptrToMe = this;
+}
+
 //================================================================================
 /*!
  * \brief Initialize global NETGEN parameters with default values
@@ -143,22 +185,24 @@ void NETGENPlugin_Mesher::SetDefaultParameters()
 {
   netgen::MeshingParameters& mparams = netgen::mparam;
   // maximal mesh edge size
-  mparams.maxh = 0;//NETGENPlugin_Hypothesis::GetDefaultMaxSize();
-  mparams.minh = 0;
+  mparams.maxh            = 0;//NETGENPlugin_Hypothesis::GetDefaultMaxSize();
+  mparams.minh            = 0;
   // minimal number of segments per edge
   mparams.segmentsperedge = NETGENPlugin_Hypothesis::GetDefaultNbSegPerEdge();
   // rate of growth of size between elements
-  mparams.grading = NETGENPlugin_Hypothesis::GetDefaultGrowthRate();
+  mparams.grading         = NETGENPlugin_Hypothesis::GetDefaultGrowthRate();
   // safety factor for curvatures (elements per radius)
   mparams.curvaturesafety = NETGENPlugin_Hypothesis::GetDefaultNbSegPerRadius();
   // create elements of second order
-  mparams.secondorder = NETGENPlugin_Hypothesis::GetDefaultSecondOrder() ? 1 : 0;
+  mparams.secondorder     = NETGENPlugin_Hypothesis::GetDefaultSecondOrder();
   // quad-dominated surface meshing
   if (_isVolume)
-    mparams.quad = 0;
+    mparams.quad          = 0;
   else
-    mparams.quad = NETGENPlugin_Hypothesis_2D::GetDefaultQuadAllowed() ? 1 : 0;
-  _fineness = NETGENPlugin_Hypothesis::GetDefaultFineness();
+    mparams.quad          = NETGENPlugin_Hypothesis_2D::GetDefaultQuadAllowed();
+  _fineness               = NETGENPlugin_Hypothesis::GetDefaultFineness();
+  mparams.uselocalh       = NETGENPlugin_Hypothesis::GetDefaultSurfaceCurvature();
+  netgen::merge_solids    = NETGENPlugin_Hypothesis::GetDefaultFuseEdges();
 }
 
 //=============================================================================
@@ -201,23 +245,25 @@ void NETGENPlugin_Mesher::SetParameters(const NETGENPlugin_Hypothesis* hyp)
     netgen::MeshingParameters& mparams = netgen::mparam;
     // Initialize global NETGEN parameters:
     // maximal mesh segment size
-    mparams.maxh = hyp->GetMaxSize();
+    mparams.maxh            = hyp->GetMaxSize();
     // maximal mesh element linear size
-    mparams.minh = hyp->GetMinSize();
+    mparams.minh            = hyp->GetMinSize();
     // minimal number of segments per edge
     mparams.segmentsperedge = hyp->GetNbSegPerEdge();
     // rate of growth of size between elements
-    mparams.grading = hyp->GetGrowthRate();
+    mparams.grading         = hyp->GetGrowthRate();
     // safety factor for curvatures (elements per radius)
     mparams.curvaturesafety = hyp->GetNbSegPerRadius();
     // create elements of second order
-    mparams.secondorder = hyp->GetSecondOrder() ? 1 : 0;
+    mparams.secondorder     = hyp->GetSecondOrder() ? 1 : 0;
     // quad-dominated surface meshing
     // only triangles are allowed for volumic mesh (before realizing IMP 0021676)
     //if (!_isVolume)
-      mparams.quad = hyp->GetQuadAllowed() ? 1 : 0;
-    _optimize = hyp->GetOptimize();
-    _fineness = hyp->GetFineness();
+      mparams.quad          = hyp->GetQuadAllowed() ? 1 : 0;
+    _optimize               = hyp->GetOptimize();
+    _fineness               = hyp->GetFineness();
+    mparams.uselocalh       = hyp->GetSurfaceCurvature();
+    netgen::merge_solids    = hyp->GetFuseEdges();
     _simpleHyp = NULL;
 
     SMESH_Gen_i* smeshGen_i = SMESH_Gen_i::GetSMESHGen();
@@ -431,11 +477,8 @@ namespace
     //   {
     //     BRepTools::Clean (shape);
         try {
-#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
           OCC_CATCH_SIGNALS;
-#endif
           BRepMesh_IncrementalMesh e(shape, 0.01, true);
-
         }
         catch (Standard_Failure)
         {
@@ -480,8 +523,9 @@ void NETGENPlugin_Mesher::PrepareOCCgeometry(netgen::OCCGeometry&     occgeo,
 
   // get root submeshes
   list< SMESH_subMesh* > rootSM;
-  if ( SMESH_subMesh* sm = mesh.GetSubMeshContaining( shape )) {
-    rootSM.push_back( sm );
+  const int shapeID = mesh.GetMeshDS()->ShapeToIndex( shape );
+  if ( shapeID > 0 ) { // SMESH_subMesh with ID 0 may exist, don't use it!
+    rootSM.push_back( mesh.GetSubMesh( shape ));
   }
   else {
     for ( TopoDS_Iterator it( shape ); it.More(); it.Next() )
@@ -1244,8 +1288,10 @@ void NETGENPlugin_Mesher::AddIntVerticesInSolids(const netgen::OCCGeometry&
 #ifdef DUMP_TRIANGLES_SCRIPT
   // create a python script making a mesh containing triangles added for internal vertices
   ofstream py(DUMP_TRIANGLES_SCRIPT);
-  py << "from smesh import * "<< endl
-     << "m = Mesh(name='triangles')" << endl;
+  py << "import SMESH"<< endl
+     << "from salome.smesh import smeshBuilder"<<endl
+     << "smesh = smeshBuilder.New(salome.myStudy)"
+     << "m = smesh.Mesh(name='triangles')" << endl;
 #endif
   if ( nodeVec.size() < ngMesh.GetNP() )
     nodeVec.resize( ngMesh.GetNP(), 0 );
@@ -1624,11 +1670,14 @@ NETGENPlugin_Mesher::AddSegmentsToMesh(netgen::Mesh&                    ngMesh,
         SMESH_TNodeXYZ np1( n ), np2( uvPtVec[ i+1 ].node );
         // get an average size of adjacent segments to avoid sharp change of
         // element size (regression on issue 0020452, note 0010898)
-        int iPrev = SMESH_MesherHelper::WrapIndex( i-1, nbSegments );
-        int iNext = SMESH_MesherHelper::WrapIndex( i+1, nbSegments );
-        double avgH = ( segLen[ iPrev ] + segLen[ i ] + segLen[ iNext ]) / 3;
-
-        RestrictLocalSize( ngMesh, 0.5*(np1+np2), avgH );
+        int   iPrev = SMESH_MesherHelper::WrapIndex( i-1, nbSegments );
+        int   iNext = SMESH_MesherHelper::WrapIndex( i+1, nbSegments );
+        double sumH = segLen[ iPrev ] + segLen[ i ] + segLen[ iNext ];
+        int   nbSeg = ( int( segLen[ iPrev ] > sumH / 100.)  +
+                        int( segLen[ i     ] > sumH / 100.)  +
+                        int( segLen[ iNext ] > sumH / 100.));
+        if ( nbSeg > 0 )
+          RestrictLocalSize( ngMesh, 0.5*(np1+np2), sumH / nbSeg );
       }
       if ( isInternalWire )
       {
@@ -2045,6 +2094,46 @@ namespace
     str << ": " << ex.What();
     return str;
   }
+
+  //================================================================================
+  /*!
+   * \brief Looks for triangles lying on a SOLID
+   */
+  //================================================================================
+
+  bool hasBadElemOnSolid( const list<const SMDS_MeshElement*>& elems,
+                          SMESH_subMesh*                       solidSM )
+  {
+    TopTools_IndexedMapOfShape solidSubs;
+    TopExp::MapShapes( solidSM->GetSubShape(), solidSubs );
+    SMESHDS_Mesh* mesh = solidSM->GetFather()->GetMeshDS();
+
+    list<const SMDS_MeshElement*>::const_iterator e = elems.begin();
+    for ( ; e != elems.end(); ++e )
+    {
+      const SMDS_MeshElement* elem = *e;
+      if ( elem->GetType() != SMDSAbs_Face )
+        continue;
+      int nbNodesOnSolid = 0;
+      SMDS_NodeIteratorPtr nIt = elem->nodeIterator();
+      while ( nIt->more() )
+      {
+        const SMDS_MeshNode* n = nIt->next();
+        const TopoDS_Shape&  s = mesh->IndexToShape( n->getshapeId() );
+        nbNodesOnSolid += ( !s.IsNull() && solidSubs.Contains( s ));
+        if ( nbNodesOnSolid > 2 )
+          return true;
+      }
+    }
+    return false;
+  }
+
+  const double edgeMeshingTime = 0.001;
+  const double faceMeshingTime = 0.019;
+  const double edgeFaceMeshingTime = edgeMeshingTime + faceMeshingTime;
+  const double faceOptimizTime = 0.06;
+  const double voluMeshingTime = 0.15;
+  const double volOptimizeTime = 0.77;
 }
 
 //=============================================================================
@@ -2055,14 +2144,8 @@ namespace
 
 bool NETGENPlugin_Mesher::Compute()
 {
-  NETGENPlugin_NetgenLibWrapper aNgLib;
-
-// Internal method is needed to get result of computation
-  return aNgLib.isComputeOk = _compute( &aNgLib );
-}
+  NETGENPlugin_NetgenLibWrapper ngLib;
 
-bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
-{
   netgen::MeshingParameters& mparams = netgen::mparam;
   MESSAGE("Compute with:\n"
           " max size = " << mparams.maxh << "\n"
@@ -2071,8 +2154,9 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
           " growth rate = " << mparams.grading << "\n"
           " elements per radius = " << mparams.curvaturesafety << "\n"
           " second order = " << mparams.secondorder << "\n"
-          " quad allowed = " << mparams.quad);
-  //cout << " quad allowed = " << mparams.quad<<endl;
+          " quad allowed = " << mparams.quad << "\n"
+          " surface curvature = " << mparams.uselocalh << "\n"
+          " fuse edges = " << netgen::merge_solids);
 
   SMESH_ComputeErrorPtr error = SMESH_ComputeError::New();
 
@@ -2086,12 +2170,23 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
   list< SMESH_subMesh* > meshedSM[3]; // for 0-2 dimensions
   NETGENPlugin_Internals internals( *_mesh, _shape, _isVolume );
   PrepareOCCgeometry( occgeo, _shape, *_mesh, meshedSM, &internals );
+  _occgeom = &occgeo;
+
+  _totalTime = edgeFaceMeshingTime;
+  if ( _optimize )
+    _totalTime += faceOptimizTime;
+  if ( _isVolume )
+    _totalTime += voluMeshingTime + ( _optimize ? volOptimizeTime : 0 );
+  double doneTime = 0;
+  _ticTime = -1;
+  _progressTic = 1;
+  _curShapeIndex = -1;
 
   // -------------------------
   // Generate the mesh
   // -------------------------
 
-  netgen::Mesh *ngMesh = NULL;
+  _ngMesh = NULL;
   NETGENPlugin_ngMeshInfo initState; // it remembers size of ng mesh equal to size of Smesh
 
   SMESH_Comment comment;
@@ -2126,7 +2221,7 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
     // Local size on faces
     occgeo.face_maxh = mparams.maxh;
 
-    // Let netgen create ngMesh and calculate element size on not meshed shapes
+    // Let netgen create _ngMesh and calculate element size on not meshed shapes
 #ifndef NETGEN_V5
     char *optstr = 0;
 #endif
@@ -2136,14 +2231,13 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
     {
       OCC_CATCH_SIGNALS;
 #ifdef NETGEN_V5
-      err = netgen::OCCGenerateMesh(occgeo, ngMesh, mparams, startWith, endWith);
+      err = netgen::OCCGenerateMesh(occgeo, _ngMesh, mparams, startWith, endWith);
 #else
-      err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
+      err = netgen::OCCGenerateMesh(occgeo, _ngMesh, startWith, endWith, optstr);
 #endif
-#ifdef WITH_SMESH_CANCEL_COMPUTE
       if(netgen::multithread.terminate)
         return false;
-#endif
+
       comment << text(err);
     }
     catch (Standard_Failure& ex)
@@ -2151,11 +2245,11 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
       comment << text(ex);
     }
     err = 0; //- MESHCONST_ANALYSE isn't so important step
-    if ( !ngMesh )
+    if ( !_ngMesh )
       return false;
-    ngLib->setMesh(( Ng_Mesh*) ngMesh );
+    ngLib.setMesh(( Ng_Mesh*) _ngMesh );
 
-    ngMesh->ClearFaceDescriptors(); // we make descriptors our-self
+    _ngMesh->ClearFaceDescriptors(); // we make descriptors our-self
 
     if ( _simpleHyp )
     {
@@ -2168,7 +2262,7 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
         const TopoDS_Edge& e = TopoDS::Edge( occgeo.emap(iE));
         if ( nbSeg )
           segSize = SMESH_Algo::EdgeLength( e ) / ( nbSeg - 0.4 );
-        setLocalSize( e, segSize, *ngMesh );
+        setLocalSize( e, segSize, *_ngMesh );
       }
     }
     else // if ( ! _simpleHyp )
@@ -2181,7 +2275,7 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
         double hi = (*it).second;
         const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key);
         const TopoDS_Edge& e = TopoDS::Edge(shape);
-        setLocalSize( e, hi, *ngMesh );
+        setLocalSize( e, hi, *_ngMesh );
       }
       for(std::map<int,double>::const_iterator it=VertexId2LocalSize.begin(); it!=VertexId2LocalSize.end(); it++)
       {
@@ -2190,7 +2284,7 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
         const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key);
         const TopoDS_Vertex& v = TopoDS::Vertex(shape);
         gp_Pnt p = BRep_Tool::Pnt(v);
-        NETGENPlugin_Mesher::RestrictLocalSize( *ngMesh, p.XYZ(), hi );
+        NETGENPlugin_Mesher::RestrictLocalSize( *_ngMesh, p.XYZ(), hi );
       }
       for(map<int,double>::const_iterator it=FaceId2LocalSize.begin();
           it!=FaceId2LocalSize.end(); it++)
@@ -2201,7 +2295,7 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
         int faceNgID = occgeo.fmap.FindIndex(shape);
         occgeo.SetFaceMaxH(faceNgID, val);
         for ( TopExp_Explorer edgeExp( shape, TopAbs_EDGE ); edgeExp.More(); edgeExp.Next() )
-          setLocalSize( TopoDS::Edge( edgeExp.Current() ), val, *ngMesh );
+          setLocalSize( TopoDS::Edge( edgeExp.Current() ), val, *_ngMesh );
       }
     }
 
@@ -2221,7 +2315,7 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
       {
         OCC_CATCH_SIGNALS;
         // compute local H on internal shapes in the main mesh
-        //OCCSetLocalMeshSize(intOccgeo, *ngMesh); it deletes ngMesh->localH
+        //OCCSetLocalMeshSize(intOccgeo, *_ngMesh); it deletes _ngMesh->localH
 
         // let netgen create a temporary mesh
 #ifdef NETGEN_V5
@@ -2229,12 +2323,11 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
 #else
         netgen::OCCGenerateMesh(intOccgeo, tmpNgMesh, startWith, endWith, optstr);
 #endif
-#ifdef WITH_SMESH_CANCEL_COMPUTE
         if(netgen::multithread.terminate)
           return false;
-#endif
+
         // copy LocalH from the main to temporary mesh
-        initState.transferLocalH( ngMesh, tmpNgMesh );
+        initState.transferLocalH( _ngMesh, tmpNgMesh );
 
         // compute mesh on internal edges
         startWith = endWith = netgen::MESHCONST_MESHEDGES;
@@ -2260,13 +2353,13 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
       nglib::Ng_DeleteMesh((nglib::Ng_Mesh*)tmpNgMesh);
     }
 
-    // Fill ngMesh with nodes and segments of computed submeshes
+    // Fill _ngMesh with nodes and segments of computed submeshes
     if ( !err )
     {
-      err = ! ( FillNgMesh(occgeo, *ngMesh, nodeVec, meshedSM[ MeshDim_0D ]) &&
-                FillNgMesh(occgeo, *ngMesh, nodeVec, meshedSM[ MeshDim_1D ]));
+      err = ! ( FillNgMesh(occgeo, *_ngMesh, nodeVec, meshedSM[ MeshDim_0D ]) &&
+                FillNgMesh(occgeo, *_ngMesh, nodeVec, meshedSM[ MeshDim_1D ]));
     }
-    initState = NETGENPlugin_ngMeshInfo(ngMesh);
+    initState = NETGENPlugin_ngMeshInfo(_ngMesh);
 
     // Compute 1d mesh
     if (!err)
@@ -2276,14 +2369,13 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
       {
         OCC_CATCH_SIGNALS;
 #ifdef NETGEN_V5
-        err = netgen::OCCGenerateMesh(occgeo, ngMesh, mparams, startWith, endWith);
+        err = netgen::OCCGenerateMesh(occgeo, _ngMesh, mparams, startWith, endWith);
 #else
-        err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
+        err = netgen::OCCGenerateMesh(occgeo, _ngMesh, startWith, endWith, optstr);
 #endif
-#ifdef WITH_SMESH_CANCEL_COMPUTE
         if(netgen::multithread.terminate)
           return false;
-#endif
+
         comment << text(err);
       }
       catch (Standard_Failure& ex)
@@ -2292,6 +2384,9 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
         err = 1;
       }
     }
+    if ( _isVolume )
+      _ticTime = ( doneTime += edgeMeshingTime ) / _totalTime / _progressTic;
+
     mparams.uselocalh = true; // restore as it is used at surface optimization
 
     // ---------------------
@@ -2308,7 +2403,7 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
         }
         else {
           // length from edges
-          if ( ngMesh->GetNSeg() ) {
+          if ( _ngMesh->GetNSeg() ) {
             double edgeLength = 0;
             TopTools_MapOfShape visitedEdges;
             for ( TopExp_Explorer exp( _shape, TopAbs_EDGE ); exp.More(); exp.Next() )
@@ -2316,8 +2411,8 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
                 edgeLength += SMESH_Algo::EdgeLength( TopoDS::Edge( exp.Current() ));
             // we have to multiply length by 2 since for each TopoDS_Edge there
             // are double set of NETGEN edges, in other words, we have to
-            // divide ngMesh->GetNSeg() by 2.
-            mparams.maxh = 2*edgeLength / ngMesh->GetNSeg();
+            // divide _ngMesh->GetNSeg() by 2.
+            mparams.maxh = 2*edgeLength / _ngMesh->GetNSeg();
           }
           else {
             mparams.maxh = 1000;
@@ -2326,10 +2421,10 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
         }
         mparams.quad = _simpleHyp->GetAllowQuadrangles();
         mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 );
-        ngMesh->SetGlobalH (mparams.maxh);
+        _ngMesh->SetGlobalH (mparams.maxh);
         netgen::Box<3> bb = occgeo.GetBoundingBox();
         bb.Increase (bb.Diam()/20);
-        ngMesh->SetLocalH (bb.PMin(), bb.PMax(), mparams.grading);
+        _ngMesh->SetLocalH (bb.PMin(), bb.PMax(), mparams.grading);
       }
 
       // Care of vertices internal in faces (issue 0020676)
@@ -2337,18 +2432,18 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
       {
         // store computed segments in SMESH in order not to create SMESH
         // edges for ng segments added by AddIntVerticesInFaces()
-        FillSMesh( occgeo, *ngMesh, initState, *_mesh, nodeVec, comment );
+        FillSMesh( occgeo, *_ngMesh, initState, *_mesh, nodeVec, comment );
         // add segments to faces with internal vertices
-        AddIntVerticesInFaces( occgeo, *ngMesh, nodeVec, internals );
-        initState = NETGENPlugin_ngMeshInfo(ngMesh);
+        AddIntVerticesInFaces( occgeo, *_ngMesh, nodeVec, internals );
+        initState = NETGENPlugin_ngMeshInfo(_ngMesh);
       }
 
       // Build viscous layers
       if ( _isViscousLayers2D )
       {
         if ( !internals.hasInternalVertexInFace() ) {
-          FillSMesh( occgeo, *ngMesh, initState, *_mesh, nodeVec, comment );
-          initState = NETGENPlugin_ngMeshInfo(ngMesh);
+          FillSMesh( occgeo, *_ngMesh, initState, *_mesh, nodeVec, comment );
+          initState = NETGENPlugin_ngMeshInfo(_ngMesh);
         }
         SMESH_ProxyMesh::Ptr viscousMesh;
         SMESH_MesherHelper   helper( *_mesh );
@@ -2359,22 +2454,22 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
           if ( !viscousMesh )
             return false;
           // exclude from computation ng segments built on EDGEs of F
-          for (int i = 1; i <= ngMesh->GetNSeg(); i++)
+          for (int i = 1; i <= _ngMesh->GetNSeg(); i++)
           {
-            netgen::Segment & seg = ngMesh->LineSegment(i);
+            netgen::Segment & seg = _ngMesh->LineSegment(i);
             if (seg.si == faceID)
               seg.si = 0;
           }
-          // add new segments to ngMesh instead of excluded ones
+          // add new segments to _ngMesh instead of excluded ones
           helper.SetSubShape( F );
           TSideVector wires =
             StdMeshers_FaceSide::GetFaceWires( F, *_mesh, /*skipMediumNodes=*/true,
                                                error, viscousMesh );
-          error = AddSegmentsToMesh( *ngMesh, occgeo, wires, helper, nodeVec );
+          error = AddSegmentsToMesh( *_ngMesh, occgeo, wires, helper, nodeVec );
 
           if ( !error ) error = SMESH_ComputeError::New();
         }
-        initState = NETGENPlugin_ngMeshInfo(ngMesh);
+        initState = NETGENPlugin_ngMeshInfo(_ngMesh);
       }
 
       // Let netgen compute 2D mesh
@@ -2384,14 +2479,13 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
       {
         OCC_CATCH_SIGNALS;
 #ifdef NETGEN_V5
-        err = netgen::OCCGenerateMesh(occgeo, ngMesh, mparams, startWith, endWith);
+        err = netgen::OCCGenerateMesh(occgeo, _ngMesh, mparams, startWith, endWith);
 #else
-        err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
+        err = netgen::OCCGenerateMesh(occgeo, _ngMesh, startWith, endWith, optstr);
 #endif
-#ifdef WITH_SMESH_CANCEL_COMPUTE
         if(netgen::multithread.terminate)
           return false;
-#endif
+
         comment << text (err);
       }
       catch (Standard_Failure& ex)
@@ -2405,14 +2499,19 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
         //err = 1; -- try to make volumes anyway
       }
     }
+    if ( _isVolume )
+    {
+      doneTime += faceMeshingTime + ( _optimize ? faceOptimizTime : 0 );
+      _ticTime = doneTime / _totalTime / _progressTic;
+    }
     // ---------------------
     // generate volume mesh
     // ---------------------
-    // Fill ngMesh with nodes and faces of computed 2D submeshes
+    // Fill _ngMesh with nodes and faces of computed 2D submeshes
     if ( !err && _isVolume && ( !meshedSM[ MeshDim_2D ].empty() || mparams.quad ))
     {
       // load SMESH with computed segments and faces
-      FillSMesh( occgeo, *ngMesh, initState, *_mesh, nodeVec, comment );
+      FillSMesh( occgeo, *_ngMesh, initState, *_mesh, nodeVec, comment );
 
       // compute pyramids on quadrangles
       SMESH_ProxyMesh::Ptr proxyMesh;
@@ -2433,13 +2532,13 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
                 quadFaceSM.push_back( _mesh->GetSubMesh( face.Current() ));
                 meshedSM[ MeshDim_2D ].remove( quadFaceSM.back() );
               }
-            FillNgMesh(occgeo, *ngMesh, nodeVec, quadFaceSM, proxyMesh);
+            FillNgMesh(occgeo, *_ngMesh, nodeVec, quadFaceSM, proxyMesh);
           }
         }
-      // fill ngMesh with faces of sub-meshes
-      err = ! ( FillNgMesh(occgeo, *ngMesh, nodeVec, meshedSM[ MeshDim_2D ]));
-      initState = NETGENPlugin_ngMeshInfo(ngMesh);
-      //toPython( ngMesh, "/tmp/ngPython.py");
+      // fill _ngMesh with faces of sub-meshes
+      err = ! ( FillNgMesh(occgeo, *_ngMesh, nodeVec, meshedSM[ MeshDim_2D ]));
+      initState = NETGENPlugin_ngMeshInfo(_ngMesh);
+      //toPython( _ngMesh, "/tmp/ngPython.py");
     }
     if (!err && _isVolume)
     {
@@ -2454,14 +2553,14 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
         }
         else {
           // length from faces
-          mparams.maxh = ngMesh->AverageH();
+          mparams.maxh = _ngMesh->AverageH();
         }
-        ngMesh->SetGlobalH (mparams.maxh);
+        _ngMesh->SetGlobalH (mparams.maxh);
         mparams.grading = 0.4;
 #ifdef NETGEN_V5
-        ngMesh->CalcLocalH(mparams.grading);
+        _ngMesh->CalcLocalH(mparams.grading);
 #else
-        ngMesh->CalcLocalH();
+        _ngMesh->CalcLocalH();
 #endif
       }
       // Care of vertices internal in solids and internal faces (issue 0020676)
@@ -2469,12 +2568,12 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
       {
         // store computed faces in SMESH in order not to create SMESH
         // faces for ng faces added here
-        FillSMesh( occgeo, *ngMesh, initState, *_mesh, nodeVec, comment );
+        FillSMesh( occgeo, *_ngMesh, initState, *_mesh, nodeVec, comment );
         // add ng faces to solids with internal vertices
-        AddIntVerticesInSolids( occgeo, *ngMesh, nodeVec, internals );
+        AddIntVerticesInSolids( occgeo, *_ngMesh, nodeVec, internals );
         // duplicate mesh faces on internal faces
-        FixIntFaces( occgeo, *ngMesh, internals );
-        initState = NETGENPlugin_ngMeshInfo(ngMesh);
+        FixIntFaces( occgeo, *_ngMesh, internals );
+        initState = NETGENPlugin_ngMeshInfo(_ngMesh);
       }
       // Let netgen compute 3D mesh
       startWith = endWith = netgen::MESHCONST_MESHVOLUME;
@@ -2482,14 +2581,13 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
       {
         OCC_CATCH_SIGNALS;
 #ifdef NETGEN_V5
-        err = netgen::OCCGenerateMesh(occgeo, ngMesh, mparams, startWith, endWith);
+        err = netgen::OCCGenerateMesh(occgeo, _ngMesh, mparams, startWith, endWith);
 #else
-        err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
+        err = netgen::OCCGenerateMesh(occgeo, _ngMesh, startWith, endWith, optstr);
 #endif
-#ifdef WITH_SMESH_CANCEL_COMPUTE
         if(netgen::multithread.terminate)
           return false;
-#endif
+
         if ( comment.empty() ) // do not overwrite a previos error
           comment << text(err);
       }
@@ -2505,6 +2603,8 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
           comment << text(exc);
         err = 1;
       }
+      _ticTime = ( doneTime += voluMeshingTime ) / _totalTime / _progressTic;
+
       // Let netgen optimize 3D mesh
       if ( !err && _optimize )
       {
@@ -2513,14 +2613,13 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
         {
           OCC_CATCH_SIGNALS;
 #ifdef NETGEN_V5
-          err = netgen::OCCGenerateMesh(occgeo, ngMesh, mparams, startWith, endWith);
+          err = netgen::OCCGenerateMesh(occgeo, _ngMesh, mparams, startWith, endWith);
 #else
-          err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
+          err = netgen::OCCGenerateMesh(occgeo, _ngMesh, startWith, endWith, optstr);
 #endif
-#ifdef WITH_SMESH_CANCEL_COMPUTE
           if(netgen::multithread.terminate)
             return false;
-#endif
+
           if ( comment.empty() ) // do not overwrite a previos error
             comment << text(err);
         }
@@ -2542,7 +2641,7 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
       {
         OCC_CATCH_SIGNALS;
         netgen::OCCRefinementSurfaces ref (occgeo);
-        ref.MakeSecondOrder (*ngMesh);
+        ref.MakeSecondOrder (*_ngMesh);
       }
       catch (Standard_Failure& ex)
       {
@@ -2556,10 +2655,13 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
       }
     }
   }
-  int nbNod = ngMesh->GetNP();
-  int nbSeg = ngMesh->GetNSeg();
-  int nbFac = ngMesh->GetNSE();
-  int nbVol = ngMesh->GetNE();
+
+  _ticTime = 0.98 / _progressTic;
+
+  int nbNod = _ngMesh->GetNP();
+  int nbSeg = _ngMesh->GetNSeg();
+  int nbFac = _ngMesh->GetNSE();
+  int nbVol = _ngMesh->GetNE();
   bool isOK = ( !err && (_isVolume ? (nbVol > 0) : (nbFac > 0)) );
 
   MESSAGE((err ? "Mesh Generation failure" : "End of Mesh Generation") <<
@@ -2570,7 +2672,7 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
 
   // Feed back the SMESHDS with the generated Nodes and Elements
   if ( true /*isOK*/ ) // get whatever built
-    FillSMesh( occgeo, *ngMesh, initState, *_mesh, nodeVec, comment ); //!< 
+    FillSMesh( occgeo, *_ngMesh, initState, *_mesh, nodeVec, comment ); //!< 
 
   SMESH_ComputeErrorPtr readErr = ReadErrors(nodeVec);
   if ( readErr && !readErr->myBadElements.empty() )
@@ -2629,7 +2731,14 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
           {
             smError.reset( new SMESH_ComputeError( *error ));
             if ( nbVol && SMESH_Algo::GetMeshError( sm ) == SMESH_Algo::MEr_OK )
+            {
               smError->myName = COMPERR_WARNING;
+            }
+            else if ( !smError->myBadElements.empty() ) // bad surface mesh
+            {
+              if ( !hasBadElemOnSolid( smError->myBadElements, sm ))
+                smError.reset();
+            }
           }
           pb3D = pb3D || ( smError && smError->IsKO() );
         }
@@ -2637,6 +2746,8 @@ bool NETGENPlugin_Mesher::_compute( NETGENPlugin_NetgenLibWrapper* ngLib )
       err = 0; // no fatal errors, only warnings
   }
 
+  ngLib._isComputeOk = !err;
+
   return !err;
 }
 
@@ -2684,7 +2795,7 @@ bool NETGENPlugin_Mesher::Evaluate(MapShapeNbElems& aResMap)
   if ( _simpleHyp || ( mparams.minh == 0.0 && _fineness != NETGENPlugin_Hypothesis::UserDefined))
     mparams.minh = GetDefaultMinSize( _shape, mparams.maxh );
 
-  // let netgen create ngMesh and calculate element size on not meshed shapes
+  // let netgen create _ngMesh and calculate element size on not meshed shapes
   NETGENPlugin_NetgenLibWrapper ngLib;
   netgen::Mesh *ngMesh = NULL;
 #ifndef NETGEN_V5
@@ -2697,10 +2808,10 @@ bool NETGENPlugin_Mesher::Evaluate(MapShapeNbElems& aResMap)
 #else
   int err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
 #endif
-#ifdef WITH_SMESH_CANCEL_COMPUTE
+
   if(netgen::multithread.terminate)
     return false;
-#endif
+
   ngLib.setMesh(( Ng_Mesh*) ngMesh );
   if (err) {
     if ( SMESH_subMesh* sm = _mesh->GetSubMeshContaining( _shape ))
@@ -2903,6 +3014,68 @@ bool NETGENPlugin_Mesher::Evaluate(MapShapeNbElems& aResMap)
   return true;
 }
 
+double NETGENPlugin_Mesher::GetProgress(const SMESH_Algo* holder,
+                                        const int *       algoProgressTic,
+                                        const double *    algoProgress) const
+{
+  ((int&) _progressTic ) = *algoProgressTic + 1;
+
+  if ( !_occgeom ) return 0;
+
+  double progress = -1;
+  if ( !_isVolume )
+  {
+    if ( _ticTime < 0 && netgen::multithread.task[0] == 'O'/*Optimizing surface*/ )
+    {
+      ((double&) _ticTime ) = edgeFaceMeshingTime / _totalTime / _progressTic;
+    }
+    else if ( !_optimize /*&& _occgeom->fmap.Extent() > 1*/ )
+    {
+      int doneShapeIndex = -1;
+      while ( doneShapeIndex+1 < _occgeom->facemeshstatus.Size() &&
+              _occgeom->facemeshstatus[ doneShapeIndex+1 ])
+        doneShapeIndex++;
+      if ( doneShapeIndex+1 != _curShapeIndex )
+      {
+        ((int&) _curShapeIndex) = doneShapeIndex+1;
+        double    doneShapeRate = _curShapeIndex / double( _occgeom->fmap.Extent() );
+        double         doneTime = edgeMeshingTime + doneShapeRate * faceMeshingTime;
+        ((double&)    _ticTime) = doneTime / _totalTime / _progressTic;
+        // cout << "shape " << _curShapeIndex << " _ticTime " << _ticTime
+        //      << " " << doneTime / _totalTime / _progressTic << endl;
+      }
+    }
+  }
+  else if ( !_optimize && _occgeom->somap.Extent() > 1 )
+  {
+    int curShapeIndex = _curShapeIndex;
+    if ( _ngMesh->GetNE() > 0 )
+    {
+      netgen::Element el = (*_ngMesh)[netgen::ElementIndex( _ngMesh->GetNE()-1 )];
+      curShapeIndex = el.GetIndex();
+    }
+    if ( curShapeIndex != _curShapeIndex )
+    {
+      ((int&) _curShapeIndex) = curShapeIndex;
+      double    doneShapeRate = _curShapeIndex / double( _occgeom->somap.Extent() );
+      double         doneTime = edgeFaceMeshingTime + doneShapeRate * voluMeshingTime;
+      ((double&)    _ticTime) = doneTime / _totalTime / _progressTic;
+      // cout << "shape " << _curShapeIndex << " _ticTime " << _ticTime
+      //      << " " << doneTime / _totalTime / _progressTic << endl;
+    }
+  }
+  if ( _ticTime > 0 )
+    progress  = Max( *algoProgressTic * _ticTime, *algoProgress );
+  if ( progress > 0 )
+  {
+    ((int&) *algoProgressTic )++;
+    ((double&) *algoProgress) = progress;
+  }
+  //cout << progress << " "  << *algoProgressTic << " " << netgen::multithread.task << " "<< _ticTime << endl;
+
+  return Min( progress, 0.99 );
+}
+
 //================================================================================
 /*!
  * \brief Remove "test.out" and "problemfaces" files in current directory
@@ -2911,11 +3084,14 @@ bool NETGENPlugin_Mesher::Evaluate(MapShapeNbElems& aResMap)
 
 void NETGENPlugin_Mesher::RemoveTmpFiles()
 {
-  if ( SMESH_File("test.out").remove() && netgen::testout)
+  bool rm =  SMESH_File("test.out").remove() ;
+#ifndef WIN32
+  if (rm && netgen::testout)
   {
     delete netgen::testout;
     netgen::testout = 0;
   }
+#endif
   SMESH_File("problemfaces").remove();
   SMESH_File("occmesh.rep").remove();
 }
@@ -2999,7 +3175,9 @@ void NETGENPlugin_Mesher::toPython( const netgen::Mesh* ngMesh,
   ofstream outfile(pyFile.c_str(), ios::out);
   if ( !outfile ) return;
 
-  outfile << "import smesh, SMESH" << endl
+  outfile << "import SMESH" << endl
+          << "from salome.smesh import smeshBuilder" << endl
+          << "smesh = smeshBuilder.New(salome.myStudy)" << endl
           << "mesh = smesh.Mesh()" << endl << endl;
 
   using namespace netgen;
@@ -3468,8 +3646,24 @@ SMESH_Mesh& NETGENPlugin_Internals::getMesh() const
 
 NETGENPlugin_NetgenLibWrapper::NETGENPlugin_NetgenLibWrapper()
 {
-  myOutputFile = getOutputFileName();
-  Ng_Init( myOutputFile.c_str() );
+  Ng_Init();
+
+  _isComputeOk      = false;
+  _coutBuffer       = NULL;
+  if ( !getenv( "KEEP_NETGEN_OUTPUT" ))
+  {
+    // redirect all netgen output (mycout,myerr,cout) to _outputFileName
+    _outputFileName = getOutputFileName();
+    netgen::mycout  = new ofstream ( _outputFileName.c_str() );
+    netgen::myerr   = netgen::mycout;
+    _coutBuffer     = std::cout.rdbuf();
+#ifdef _DEBUG_
+    cout << "NOTE: netgen output is redirected to file " << _outputFileName << endl;
+#else
+    std::cout.rdbuf( netgen::mycout->rdbuf() );
+#endif
+  }
+
   _ngMesh = Ng_NewMesh();
 }
 
@@ -3484,8 +3678,12 @@ NETGENPlugin_NetgenLibWrapper::~NETGENPlugin_NetgenLibWrapper()
   Ng_DeleteMesh( _ngMesh );
   Ng_Exit();
   NETGENPlugin_Mesher::RemoveTmpFiles();
-  if( isComputeOk )
-    RemoveOutputFile();
+  if ( _coutBuffer )
+    std::cout.rdbuf( _coutBuffer );
+#ifdef _DEBUG_
+  if( _isComputeOk )
+#endif
+    removeOutputFile();
 }
 
 //================================================================================
@@ -3513,7 +3711,11 @@ std::string NETGENPlugin_NetgenLibWrapper::getOutputFileName()
 
   TCollection_AsciiString aGenericName = (char*)aTmpDir.c_str();
   aGenericName += "NETGEN_";
+#ifndef WIN32
   aGenericName += getpid();
+#else
+  aGenericName += _getpid();
+#endif
   aGenericName += "_";
   aGenericName += Abs((Standard_Integer)(long) aGenericName.ToCString());
   aGenericName += ".out";
@@ -3527,13 +3729,22 @@ std::string NETGENPlugin_NetgenLibWrapper::getOutputFileName()
  */
 //================================================================================
 
-void NETGENPlugin_NetgenLibWrapper::RemoveOutputFile()
+void NETGENPlugin_NetgenLibWrapper::removeOutputFile()
 {
-  string tmpDir = SALOMEDS_Tool::GetDirFromPath( myOutputFile );
-  SALOMEDS::ListOfFileNames_var aFiles = new SALOMEDS::ListOfFileNames;
-  aFiles->length(1);
-  std::string aFileName = SALOMEDS_Tool::GetNameFromPath( myOutputFile ) + ".out";
-  aFiles[0] = aFileName.c_str();
-  
-  SALOMEDS_Tool::RemoveTemporaryFiles( tmpDir.c_str(), aFiles.in(), true );
+  if ( !_outputFileName.empty() )
+  {
+    if ( netgen::mycout )
+    {
+      delete netgen::mycout;
+      netgen::mycout = 0;
+      netgen::myerr = 0;
+    }
+    string    tmpDir = SALOMEDS_Tool::GetDirFromPath ( _outputFileName );
+    string aFileName = SALOMEDS_Tool::GetNameFromPath( _outputFileName ) + ".out";
+    SALOMEDS::ListOfFileNames_var aFiles = new SALOMEDS::ListOfFileNames;
+    aFiles->length(1);
+    aFiles[0] = aFileName.c_str();
+
+    SALOMEDS_Tool::RemoveTemporaryFiles( tmpDir.c_str(), aFiles.in(), true );
+  }
 }