+ const int nb = (int)( 1.5 * SMESH_Algo::EdgeLength( edge ) / size );
+ Standard_Real delta = (u2-u1)/nb;
+ for(int i=0; i<nb; i++)
+ {
+ Standard_Real u = u1 + delta*i;
+ gp_Pnt p = curve->Value(u);
+ NETGENPlugin_Mesher::RestrictLocalSize( mesh, p.XYZ(), size, overrideMinH );
+ netgen::Point3d pi(p.X(), p.Y(), p.Z());
+ double resultSize = mesh.GetH(pi);
+ if ( resultSize - size > 0.1*size )
+ // netgen does restriction iff oldH/newH > 1.2 (localh.cpp:136)
+ NETGENPlugin_Mesher::RestrictLocalSize( mesh, p.XYZ(), resultSize/1.201, overrideMinH );
+ }
+ }
+ }
+
+ //================================================================================
+ /*!
+ * \brief Return triangle size for a given chordalError and radius of curvature
+ */
+ //================================================================================
+
+ double elemSizeForChordalError( double chordalError, double radius )
+ {
+ if ( 2 * radius < chordalError )
+ return 1.5 * radius;
+ return Sqrt( 3 ) * Sqrt( chordalError * ( 2 * radius - chordalError ));
+ }
+
+ //=============================================================================
+ /*!
+ *
+ */
+ //=============================================================================
+
+ void setLocalSize(const TopoDS_Shape& GeomShape, double LocalSize)
+ {
+ if ( GeomShape.IsNull() ) return;
+ TopAbs_ShapeEnum GeomType = GeomShape.ShapeType();
+ if (GeomType == TopAbs_COMPOUND) {
+ for (TopoDS_Iterator it (GeomShape); it.More(); it.Next()) {
+ setLocalSize(it.Value(), LocalSize);
+ }
+ return;
+ }
+ int key;
+ if (! ShapesWithLocalSize.Contains(GeomShape))
+ key = ShapesWithLocalSize.Add(GeomShape);
+ else
+ key = ShapesWithLocalSize.FindIndex(GeomShape);
+ if (GeomType == TopAbs_VERTEX) {
+ VertexId2LocalSize[key] = LocalSize;
+ } else if (GeomType == TopAbs_EDGE) {
+ EdgeId2LocalSize[key] = LocalSize;
+ } else if (GeomType == TopAbs_FACE) {
+ FaceId2LocalSize[key] = LocalSize;
+ } else if (GeomType == TopAbs_SOLID) {
+ SolidId2LocalSize[key] = LocalSize;
+ }
+ return;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Return faceNgID or faceNgID-1 depending on side the given proxy face lies
+ * \param [in] f - proxy face
+ * \param [in] solidSMDSIDs - IDs of SOLIDs sharing the FACE on which face lies
+ * \param [in] faceNgID - NETGEN ID of the FACE
+ * \return int - NETGEN ID of the FACE
+ */
+ //================================================================================
+
+ int getFaceNgID( const SMDS_MeshElement* face,
+ const int * solidSMDSIDs,
+ const int faceNgID )
+ {
+ for ( int i = 0; i < 3; ++i )
+ {
+ const SMDS_MeshNode* n = face->GetNode( i );
+ const int shapeID = n->GetShapeID();
+ if ( shapeID == solidSMDSIDs[0] )
+ return faceNgID - 1;
+ if ( shapeID == solidSMDSIDs[1] )
+ return faceNgID;
+ }
+ std::vector<const SMDS_MeshNode*> fNodes( face->begin_nodes(), face->end_nodes() );
+ std::vector<const SMDS_MeshElement*> vols;
+ if ( SMDS_Mesh::GetElementsByNodes( fNodes, vols, SMDSAbs_Volume ))
+ for ( size_t i = 0; i < vols.size(); ++i )
+ {
+ const int shapeID = vols[i]->GetShapeID();
+ if ( shapeID == solidSMDSIDs[0] )
+ return faceNgID - 1;
+ if ( shapeID == solidSMDSIDs[1] )
+ return faceNgID;
+ }
+ return faceNgID;
+ }
+
+} // namespace
+
+//=============================================================================
+/*!
+ *
+ */
+//=============================================================================
+
+NETGENPlugin_Mesher::NETGENPlugin_Mesher (SMESH_Mesh* mesh,
+ const TopoDS_Shape& aShape,
+ const bool isVolume)
+ : _mesh (mesh),
+ _shape (aShape),
+ _isVolume(isVolume),
+ _optimize(true),
+ _fineness(NETGENPlugin_Hypothesis::GetDefaultFineness()),
+ _isViscousLayers2D(false),
+ _chordalError(-1), // means disabled
+ _ngMesh(NULL),
+ _occgeom(NULL),
+ _curShapeIndex(-1),
+ _progressTic(1),
+ _totalTime(1.0),
+ _simpleHyp(NULL),
+ _viscousLayersHyp(NULL),
+ _ptrToMe(NULL)
+{
+ SetDefaultParameters();
+ ShapesWithLocalSize.Clear();
+ VertexId2LocalSize.clear();
+ EdgeId2LocalSize.clear();
+ FaceId2LocalSize.clear();
+ SolidId2LocalSize.clear();
+ ControlPoints.clear();
+ ShapesWithControlPoints.clear();
+}
+
+//================================================================================
+/*!
+ * Destructor
+ */
+//================================================================================
+
+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
+ */
+//================================================================================
+
+void NETGENPlugin_Mesher::SetDefaultParameters()
+{
+ netgen::MeshingParameters& mparams = netgen::mparam;
+ mparams = netgen::MeshingParameters();
+ // maximal mesh edge size
+ 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();
+ // safety factor for curvatures (elements per radius)
+ mparams.curvaturesafety = NETGENPlugin_Hypothesis::GetDefaultNbSegPerRadius();
+ // create elements of second order
+ mparams.secondorder = NETGENPlugin_Hypothesis::GetDefaultSecondOrder();
+ // quad-dominated surface meshing
+ if (_isVolume)
+ mparams.quad = 0;
+ else
+ mparams.quad = NETGENPlugin_Hypothesis_2D::GetDefaultQuadAllowed();
+ _fineness = NETGENPlugin_Hypothesis::GetDefaultFineness();
+ mparams.uselocalh = NETGENPlugin_Hypothesis::GetDefaultSurfaceCurvature();
+ netgen::merge_solids = NETGENPlugin_Hypothesis::GetDefaultFuseEdges();
+}
+
+//=============================================================================
+/*!
+ * Pass parameters to NETGEN
+ */
+//=============================================================================
+void NETGENPlugin_Mesher::SetParameters(const NETGENPlugin_Hypothesis* hyp)
+{
+ if (hyp)
+ {
+ netgen::MeshingParameters& mparams = netgen::mparam;
+ // Initialize global NETGEN parameters:
+ // maximal mesh segment size
+ mparams.maxh = hyp->GetMaxSize();
+ // maximal mesh element linear size
+ 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();
+ // safety factor for curvatures (elements per radius)
+ mparams.curvaturesafety = hyp->GetNbSegPerRadius();
+ // create elements of second order
+ mparams.secondorder = hyp->GetSecondOrder() ? 1 : 0;
+ // quad-dominated surface meshing
+ mparams.quad = hyp->GetQuadAllowed() ? 1 : 0;
+ _optimize = hyp->GetOptimize();
+ _fineness = hyp->GetFineness();
+ mparams.uselocalh = hyp->GetSurfaceCurvature();
+ netgen::merge_solids = hyp->GetFuseEdges();
+ _chordalError = hyp->GetChordalErrorEnabled() ? hyp->GetChordalError() : -1.;
+ mparams.optsteps2d = _optimize ? hyp->GetNbSurfOptSteps() : 0;
+ mparams.optsteps3d = _optimize ? hyp->GetNbVolOptSteps() : 0;
+ mparams.elsizeweight = hyp->GetElemSizeWeight();
+ mparams.opterrpow = hyp->GetWorstElemMeasure();
+ mparams.delaunay = hyp->GetUseDelauney();
+ mparams.checkoverlap = hyp->GetCheckOverlapping();
+ mparams.checkchartboundary = hyp->GetCheckChartBoundary();
+ _simpleHyp = NULL;
+ // mesh size file
+ mparams.meshsizefilename= hyp->GetMeshSizeFile().empty() ? 0 : hyp->GetMeshSizeFile().c_str();
+
+ const NETGENPlugin_Hypothesis::TLocalSize& localSizes = hyp->GetLocalSizesAndEntries();
+ if ( !localSizes.empty() )
+ {
+ SMESH_Gen_i* smeshGen_i = SMESH_Gen_i::GetSMESHGen();
+ NETGENPlugin_Hypothesis::TLocalSize::const_iterator it = localSizes.begin();
+ for ( ; it != localSizes.end() ; it++)
+ {
+ std::string entry = (*it).first;
+ double val = (*it).second;
+ // --
+ GEOM::GEOM_Object_var aGeomObj;
+ SALOMEDS::SObject_var aSObj = SMESH_Gen_i::getStudyServant()->FindObjectID( entry.c_str() );
+ if ( !aSObj->_is_nil() ) {
+ CORBA::Object_var obj = aSObj->GetObject();
+ aGeomObj = GEOM::GEOM_Object::_narrow(obj);
+ aSObj->UnRegister();
+ }
+ TopoDS_Shape S = smeshGen_i->GeomObjectToShape( aGeomObj.in() );
+ setLocalSize(S, val);
+ }
+ }
+ }
+}
+
+//=============================================================================
+/*!
+ * Pass simple parameters to NETGEN
+ */
+//=============================================================================
+
+void NETGENPlugin_Mesher::SetParameters(const NETGENPlugin_SimpleHypothesis_2D* hyp)
+{
+ _simpleHyp = hyp;
+ if ( _simpleHyp )
+ SetDefaultParameters();
+}
+
+//================================================================================
+/*!
+ * \brief Store a Viscous Layers hypothesis
+ */
+//================================================================================
+
+void NETGENPlugin_Mesher::SetParameters(const StdMeshers_ViscousLayers* hyp )
+{
+ _viscousLayersHyp = hyp;
+}
+
+//================================================================================
+/*!
+ * \brief Set local size on shapes defined by SetParameters()
+ */
+//================================================================================
+
+void NETGENPlugin_Mesher::SetLocalSize( netgen::OCCGeometry& occgeo,
+ netgen::Mesh& ngMesh)
+{
+ // edges
+ std::map<int,double>::const_iterator it;
+ for( it=EdgeId2LocalSize.begin(); it!=EdgeId2LocalSize.end(); it++)
+ {
+ int key = (*it).first;
+ double hi = (*it).second;
+ const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key);
+ setLocalSize( TopoDS::Edge(shape), hi, ngMesh );
+ }
+ // vertices
+ for(it=VertexId2LocalSize.begin(); it!=VertexId2LocalSize.end(); it++)
+ {
+ int key = (*it).first;
+ double hi = (*it).second;
+ const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key);
+ gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex(shape) );
+ NETGENPlugin_Mesher::RestrictLocalSize( ngMesh, p.XYZ(), hi );
+ }
+ // faces
+ for(it=FaceId2LocalSize.begin(); it!=FaceId2LocalSize.end(); it++)
+ {
+ int key = (*it).first;
+ double val = (*it).second;
+ const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key);
+ int faceNgID = occgeo.fmap.FindIndex(shape);
+ if ( faceNgID >= 1 )
+ {
+ occgeo.SetFaceMaxH(faceNgID, val);
+ for ( TopExp_Explorer edgeExp( shape, TopAbs_EDGE ); edgeExp.More(); edgeExp.Next() )
+ setLocalSize( TopoDS::Edge( edgeExp.Current() ), val, ngMesh );
+ }
+ else if ( !ShapesWithControlPoints.count( key ))
+ {
+ SMESHUtils::createPointsSampleFromFace( TopoDS::Face( shape ), val, ControlPoints );
+ ShapesWithControlPoints.insert( key );
+ }
+ }
+ //solids
+ for(it=SolidId2LocalSize.begin(); it!=SolidId2LocalSize.end(); it++)
+ {
+ int key = (*it).first;
+ double val = (*it).second;
+ if ( !ShapesWithControlPoints.count( key ))
+ {
+ const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key);
+ SMESHUtils::createPointsSampleFromSolid( TopoDS::Solid( shape ), val, ControlPoints );
+ ShapesWithControlPoints.insert( key );
+ }
+ }
+
+ if ( !ControlPoints.empty() )
+ {
+ for ( size_t i = 0; i < ControlPoints.size(); ++i )
+ NETGENPlugin_Mesher::RestrictLocalSize( ngMesh, ControlPoints[i].XYZ(), ControlPoints[i].Size() );
+ }
+ return;
+}
+
+//================================================================================
+/*!
+ * \brief Restrict local size to achieve a required _chordalError
+ */
+//================================================================================
+
+void NETGENPlugin_Mesher::SetLocalSizeForChordalError( netgen::OCCGeometry& occgeo,
+ netgen::Mesh& ngMesh)
+{
+ if ( _chordalError <= 0. )
+ return;
+
+ TopLoc_Location loc;
+ BRepLProp_SLProps surfProp( 2, 1e-6 );
+ const double sizeCoef = 0.95;
+
+ // find non-planar FACEs with non-constant curvature
+ std::vector<int> fInd;
+ for ( int i = 1; i <= occgeo.fmap.Extent(); ++i )
+ {
+ const TopoDS_Face& face = TopoDS::Face( occgeo.fmap( i ));
+ BRepAdaptor_Surface surfAd( face, false );
+ switch ( surfAd.GetType() )
+ {
+ case GeomAbs_Plane:
+ continue;
+ case GeomAbs_Cylinder:
+ case GeomAbs_Sphere:
+ case GeomAbs_Torus: // constant curvature
+ {
+ surfProp.SetSurface( surfAd );
+ surfProp.SetParameters( 0, 0 );
+ double maxCurv = Max( Abs( surfProp.MaxCurvature()), Abs( surfProp.MinCurvature() ));
+ double size = elemSizeForChordalError( _chordalError, 1 / maxCurv );
+ occgeo.SetFaceMaxH( i, size * sizeCoef );
+ // limit size one edges
+ TopTools_MapOfShape edgeMap;
+ for ( TopExp_Explorer eExp( face, TopAbs_EDGE ); eExp.More(); eExp.Next() )
+ if ( edgeMap.Add( eExp.Current() ))
+ setLocalSize( TopoDS::Edge( eExp.Current() ), size, ngMesh, /*overrideMinH=*/false );
+ break;
+ }
+ default:
+ Handle(Geom_Surface) surf = BRep_Tool::Surface( face, loc );
+ if ( GeomLib_IsPlanarSurface( surf ).IsPlanar() )