From: rnv Date: Fri, 29 Dec 2017 13:22:02 +0000 (+0300) Subject: Merge changes from 'master' branch. X-Git-Tag: V9_0_0~1 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=ac5dc648d839444366920d17980ba1690355bf25;p=plugins%2Fnetgenplugin.git Merge changes from 'master' branch. --- ac5dc648d839444366920d17980ba1690355bf25 diff --cc src/NETGENPlugin/NETGENPluginBuilder.py index 932500d,7334ae3..edf7df7 --- a/src/NETGENPlugin/NETGENPluginBuilder.py +++ b/src/NETGENPlugin/NETGENPluginBuilder.py @@@ -105,8 -105,12 +105,12 @@@ class NETGEN_Algorithm(Mesh_Algorithm) # if it is @c 0 (default), the algorithm is assigned to the main shape def __init__(self, mesh, geom=0): Mesh_Algorithm.__init__(self) - if noNETGENPlugin: print "Warning: NETGENPlugin module unavailable" + if noNETGENPlugin: print("Warning: NETGENPlugin module unavailable") - self.Create(mesh, geom, self.algoType, LIBRARY) + if not mesh.GetMesh().HasShapeToMesh() and \ + self.meshMethod == "Triangle": # create a 2D remesher + self.Create(mesh, geom, "NETGEN_Remesher_2D", LIBRARY) + else: + self.Create(mesh, geom, self.algoType, LIBRARY) self.params = None pass diff --cc src/NETGENPlugin/NETGENPlugin_Hypothesis.cxx index 5ec88e3,9bd9ec8..abb5b6a --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis.cxx @@@ -40,21 -40,23 +40,24 @@@ using namespace std * */ //============================================================================= -NETGENPlugin_Hypothesis::NETGENPlugin_Hypothesis (int hypId, int studyId, +NETGENPlugin_Hypothesis::NETGENPlugin_Hypothesis (int hypId, SMESH_Gen * gen) - : SMESH_Hypothesis(hypId, studyId, gen), ++ + : SMESH_Hypothesis(hypId, gen), - _maxSize (GetDefaultMaxSize()), - _minSize (0), - _growthRate (GetDefaultGrowthRate()), - _nbSegPerEdge (GetDefaultNbSegPerEdge()), - _nbSegPerRadius (GetDefaultNbSegPerRadius()), - _fineness (GetDefaultFineness()), - _secondOrder (GetDefaultSecondOrder()), - _optimize (GetDefaultOptimize()), - _localSize (GetDefaultLocalSize()), - _quadAllowed (GetDefaultQuadAllowed()), - _surfaceCurvature(GetDefaultSurfaceCurvature()), - _fuseEdges (GetDefaultFuseEdges()) + _maxSize (GetDefaultMaxSize()), + _minSize (0), + _growthRate (GetDefaultGrowthRate()), + _nbSegPerEdge (GetDefaultNbSegPerEdge()), + _nbSegPerRadius (GetDefaultNbSegPerRadius()), + _fineness (GetDefaultFineness()), + _chordalErrorEnabled(GetDefaultChordalError() > 0), + _chordalError (GetDefaultChordalError() ), + _secondOrder (GetDefaultSecondOrder()), + _optimize (GetDefaultOptimize()), + _localSize (GetDefaultLocalSize()), + _quadAllowed (GetDefaultQuadAllowed()), + _surfaceCurvature (GetDefaultSurfaceCurvature()), + _fuseEdges (GetDefaultFuseEdges()) { _name = "NETGEN_Parameters"; _param_algo_dim = 3; diff --cc src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.cxx index 6dfa5ac,5db5097..d7f52e8 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.cxx @@@ -51,56 -50,72 +50,72 @@@ NETGENPlugin_Hypothesis_2D::NETGENPlugi * */ //============================================================================= - // void NETGENPlugin_Hypothesis_2D::SetQuadAllowed(bool theVal) - // { - // if (theVal != _quadAllowed) - // { - // _quadAllowed = theVal; - // NotifySubMeshesHypothesisModification(); - // } - // } - - // //============================================================================= - // /*! - // * - // */ - // //============================================================================= - // bool NETGENPlugin_Hypothesis_2D::GetDefaultQuadAllowed() - // { - // return false; - // } - - // //============================================================================= - // /*! - // * - // */ - // //============================================================================= - // ostream & NETGENPlugin_Hypothesis_2D::SaveTo(ostream & save) - // { - // NETGENPlugin_Hypothesis::SaveTo(save); - - // save << " " << (int)_quadAllowed; - - // return save; - // } - - // //============================================================================= - // /*! - // * - // */ - // //============================================================================= - // istream & NETGENPlugin_Hypothesis_2D::LoadFrom(istream & load) - // { - // NETGENPlugin_Hypothesis::LoadFrom(load); - - // bool isOK = true; - // int is; - - // isOK = (load >> is); - // if (isOK) - // _quadAllowed = (bool) is; - // else - // load.clear(ios::badbit | load.rdstate()); - - // return load; - // } + NETGENPlugin_RemesherHypothesis_2D:: -NETGENPlugin_RemesherHypothesis_2D (int hypId, int studyId, SMESH_Gen * gen) - : NETGENPlugin_Hypothesis(hypId, studyId, gen) ++NETGENPlugin_RemesherHypothesis_2D (int hypId, SMESH_Gen * gen) ++ : NETGENPlugin_Hypothesis(hypId, gen) + { + _name = "NETGEN_RemesherParameters_2D"; + _param_algo_dim = 2; + + _ridgeAngle = DefaultRidgeAngle(); + } + + //============================================================================= + /*! + * + */ + //============================================================================= + + void NETGENPlugin_RemesherHypothesis_2D::SetRidgeAngle( double angle ) + { + if ( _ridgeAngle != angle ) + { + _ridgeAngle = angle; + NotifySubMeshesHypothesisModification(); + } + } + + //============================================================================= + /*! + * + */ + //============================================================================= + + double NETGENPlugin_RemesherHypothesis_2D::GetRidgeAngle() const + { + return _ridgeAngle; + } + + //============================================================================= + /*! + * + */ + //============================================================================= + + std::ostream & NETGENPlugin_RemesherHypothesis_2D::SaveTo(std::ostream & save) + { + NETGENPlugin_Hypothesis::SaveTo( save ); + save << " " << _ridgeAngle; + + return save; + } + + //============================================================================= + /*! + * + */ + //============================================================================= + + std::istream & NETGENPlugin_RemesherHypothesis_2D::LoadFrom(std::istream & load) + { + NETGENPlugin_Hypothesis::LoadFrom( load ); + if ( !load ) + load.clear(ios::badbit | load.rdstate()); + + load >> _ridgeAngle; + + if ( !load ) + _ridgeAngle = DefaultRidgeAngle(); + + return load; + } diff --cc src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.hxx index a249442,cd0fe5c..877e995 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.hxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.hxx @@@ -57,4 -57,27 +57,27 @@@ public // bool _quadAllowed; }; + + // Parameters of NETGEN remesher + // + + class NETGENPLUGIN_EXPORT NETGENPlugin_RemesherHypothesis_2D: public NETGENPlugin_Hypothesis + { + public: + - NETGENPlugin_RemesherHypothesis_2D(int hypId, int studyId, SMESH_Gen * gen); ++ NETGENPlugin_RemesherHypothesis_2D(int hypId, SMESH_Gen * gen); + + void SetRidgeAngle( double angle ); + double GetRidgeAngle() const; + + static double DefaultRidgeAngle() { return 30.; } + + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); + + private: + + double _ridgeAngle; // in degrees + }; + #endif diff --cc src/NETGENPlugin/NETGENPlugin_Hypothesis_2D_i.cxx index 58683c6,d9cbde4..2a2ffa3 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D_i.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D_i.cxx @@@ -87,15 -93,37 +91,35 @@@ CORBA::Boolean NETGENPlugin_Hypothesis_ //============================================================================= /*! - * NETGENPlugin_Hypothesis_2D_i::GetQuadAllowed + * NETGENPlugin_RemesherHypothesis_2D_i::NETGENPlugin_RemesherHypothesis_2D_i * - * Get QuadAllowed flag + * Constructor */ //============================================================================= - // CORBA::Boolean NETGENPlugin_Hypothesis_2D_i::GetQuadAllowed() - // { - // return this->GetImpl()->GetQuadAllowed(); - // } + NETGENPlugin_RemesherHypothesis_2D_i:: + NETGENPlugin_RemesherHypothesis_2D_i (PortableServer::POA_ptr thePOA, - int theStudyId, + ::SMESH_Gen* theGenImpl) + : SALOME::GenericObj_i( thePOA ), + SMESH_Hypothesis_i( thePOA ), - NETGENPlugin_Hypothesis_2D_i( thePOA, theStudyId, theGenImpl ) ++ NETGENPlugin_Hypothesis_2D_i( thePOA, theGenImpl ) + { + myBaseImpl = new ::NETGENPlugin_RemesherHypothesis_2D (theGenImpl->GetANewId(), - theStudyId, + theGenImpl); + } + + //================================================================================ + /*! + * \brief Verify whether hypothesis supports given entity type + * \param type - dimension (see SMESH::Dimension enumeration) + * \retval CORBA::Boolean - TRUE if dimension is supported, FALSE otherwise + * + * Verify whether hypothesis supports given entity type (see SMESH::Dimension enumeration) + */ + //================================================================================ + CORBA::Boolean NETGENPlugin_RemesherHypothesis_2D_i::IsDimSupported( SMESH::Dimension type ) + { + return type == SMESH::DIM_2D; + } //============================================================================= /*! diff --cc src/NETGENPlugin/NETGENPlugin_Hypothesis_2D_i.hxx index 6d0fabe,876a361..a3bfa8d --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D_i.hxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D_i.hxx @@@ -69,4 -70,27 +69,26 @@@ class NETGENPLUGIN_EXPORT NETGENPlugin // }; }; + // NETGENPlugin_Remesher_2D parameters hypothesis + + class NETGENPLUGIN_EXPORT NETGENPlugin_RemesherHypothesis_2D_i: + public virtual POA_NETGENPlugin::NETGENPlugin_RemesherHypothesis_2D, + public NETGENPlugin_Hypothesis_2D_i + { + public: + // Constructor + NETGENPlugin_RemesherHypothesis_2D_i( PortableServer::POA_ptr thePOA, - int theStudyId, + ::SMESH_Gen* theGenImpl); + + void SetRidgeAngle( CORBA::Double angle ); + + CORBA::Double GetRidgeAngle(); + + // Get implementation + ::NETGENPlugin_RemesherHypothesis_2D* GetImpl(); + + // Verify whether hypothesis supports given entity type + CORBA::Boolean IsDimSupported( SMESH::Dimension type ); + }; + #endif diff --cc src/NETGENPlugin/NETGENPlugin_Mesher.cxx index 73e8c6d,6d585e0..148b0d6 --- a/src/NETGENPlugin/NETGENPlugin_Mesher.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Mesher.cxx @@@ -297,24 -307,32 +307,26 @@@ void NETGENPlugin_Mesher::SetParameters // mesh size file mparams.meshsizefilename= hyp->GetMeshSizeFile().empty() ? 0 : hyp->GetMeshSizeFile().c_str(); - SMESH_Gen_i* smeshGen_i = SMESH_Gen_i::GetSMESHGen(); - - const NETGENPlugin_Hypothesis::TLocalSize localSizes = hyp->GetLocalSizesAndEntries(); - NETGENPlugin_Hypothesis::TLocalSize::const_iterator it = localSizes.begin(); - for ( ; it != localSizes.end() ; it++) + const NETGENPlugin_Hypothesis::TLocalSize& localSizes = hyp->GetLocalSizesAndEntries(); + if ( !localSizes.empty() ) { - 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); - SMESH_Gen_i* smeshGen_i = SMESH_Gen_i::GetSMESHGen(); - CORBA::Object_var anObject = smeshGen_i->GetNS()->Resolve("/myStudyManager"); - SALOMEDS::StudyManager_var aStudyMgr = SALOMEDS::StudyManager::_narrow(anObject); - SALOMEDS::Study_var myStudy = aStudyMgr->GetStudyByID(hyp->GetStudyId()); - if ( !myStudy->_is_nil() ) ++ SMESH_Gen_i* smeshGen_i = SMESH_Gen_i::GetSMESHGen(); ++ NETGENPlugin_Hypothesis::TLocalSize::const_iterator it = localSizes.begin(); ++ for ( ; it != localSizes.end() ; it++) + { - 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 = myStudy->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); ++ 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); + } } } } diff --cc src/NETGENPlugin/NETGENPlugin_NETGEN_2D_i.cxx index 437cf3e,be39bd8..12ffdc4 --- a/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_i.cxx +++ b/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_i.cxx @@@ -77,3 -75,38 +73,36 @@@ NETGENPlugin_NETGEN_2D_i::~NETGENPlugin { return ( ::NETGENPlugin_NETGEN_2D* )myBaseImpl; } + + + + //============================================================================= + /*! + * NETGENPlugin_Remesher_2D_i::NETGENPlugin_Remesher_2D_i + * + * Constructor + */ + //============================================================================= + + NETGENPlugin_Remesher_2D_i::NETGENPlugin_Remesher_2D_i( PortableServer::POA_ptr thePOA, - int theStudyId, + ::SMESH_Gen* theGenImpl ) + : SALOME::GenericObj_i( thePOA ), + SMESH_Hypothesis_i( thePOA ), + SMESH_Algo_i( thePOA ), + SMESH_2D_Algo_i( thePOA ) + { + myBaseImpl = new ::NETGENPlugin_Remesher_2D( theGenImpl->GetANewId(), - theStudyId, + theGenImpl ); + } + + //============================================================================= + /*! + * NETGENPlugin_Remesher_2D_i::~NETGENPlugin_Remesher_2D_i + * + * Destructor + */ + //============================================================================= + + NETGENPlugin_Remesher_2D_i::~NETGENPlugin_Remesher_2D_i() + { + } diff --cc src/NETGENPlugin/NETGENPlugin_NETGEN_2D_i.hxx index bfebf5f,ea9f210..f32c9a9 --- a/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_i.hxx +++ b/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_i.hxx @@@ -55,4 -56,23 +55,22 @@@ public ::NETGENPlugin_NETGEN_2D* GetImpl(); }; + // ====================================================== + // NETGEN 2D remesher algorithm + // ====================================================== + class NETGENPLUGIN_EXPORT NETGENPlugin_Remesher_2D_i: + public virtual POA_NETGENPlugin::NETGENPlugin_Remesher_2D, + public virtual SMESH_2D_Algo_i + { + public: + // Constructor + NETGENPlugin_Remesher_2D_i( PortableServer::POA_ptr thePOA, - int theStudyId, + ::SMESH_Gen* theGenImpl ); + // Destructor + virtual ~NETGENPlugin_Remesher_2D_i(); + + // Get implementation + //::NETGENPlugin_NETGEN_2D* GetImpl(); + }; + #endif diff --cc src/NETGENPlugin/NETGENPlugin_Remesher_2D.cxx index 0000000,08f05b5..7f1f463 mode 000000,100644..100644 --- a/src/NETGENPlugin/NETGENPlugin_Remesher_2D.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Remesher_2D.cxx @@@ -1,0 -1,734 +1,734 @@@ + // Copyright (C) 2007-2016 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 + // + // 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, 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 + // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + // Lesser General Public License for more details. + // + // You should have received a copy of the GNU Lesser General Public + // License along with this library; if not, write to the Free Software + // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + // + // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com + // + // File : NETGENPlugin_Remesher_2D.cxx + // Created : Thu Sep 21 16:48:46 2017 + // Author : Edward AGAPOV (eap) + // + + #include "NETGENPlugin_Remesher_2D.hxx" + + #include "NETGENPlugin_Mesher.hxx" + #include "NETGENPlugin_Hypothesis_2D.hxx" + + #include + #include + #include + #include + #include + #include + #include + + #include + #include + + #include + #include + #include + //#include + + #include + + using namespace nglib; + + // namespace netgen + // { + // #if defined(NETGEN_V5) && defined(WIN32) + // DLL_HEADER + // #endif + // extern STLParameters stlparam; + // } + + namespace + { + //============================================================================= + /*! + * \brief Fill holes in the mesh, since netgen can remesh only a closed shell mesh. + * At destruction, remove triangles filling the holes + */ + class HoleFiller + { + public: + HoleFiller( SMESH_Mesh& meshDS ); + ~HoleFiller(); + void AddHoleBorders( Ng_STL_Geometry * ngStlGeo ); + void KeepHole() { myHole.clear(); myCapElems.clear(); } + void ClearCapElements() { myCapElems.clear(); } + + private: + SMESHDS_Mesh* myMeshDS; + std::vector< std::vector< gp_XYZ > > myHole; // initial border nodes + std::vector< gp_XYZ > myInHolePos; // position inside each hole + std::vector< const SMDS_MeshElement* > myCapElems; // elements closing holes + }; + + //================================================================================ + /*! + * \brief Fill holes in the mesh + */ + //================================================================================ + + HoleFiller::HoleFiller( SMESH_Mesh& theMesh ): + myMeshDS( theMesh.GetMeshDS() ) + { + SMESH_MeshEditor editor( &theMesh ); + { + // // merge nodes + // const double tol = Max( 0.1 * netgen::mparam.minh, Precision::Confusion() ); + // TIDSortedNodeSet allNodes; + // SMESH_MeshEditor::TListOfListOfNodes equalNodes; + // editor.FindCoincidentNodes( allNodes, tol, equalNodes, true ); + // editor.MergeNodes( equalNodes, /*noHoles=*/false ); + } + + // find holes + SMESH_MeshAlgos::TFreeBorderVec holes; + bool isManifold = true, isGoodOri = true; + SMESH_MeshAlgos::FindFreeBorders( *myMeshDS, holes, /*closedOnly=*/true, + &isManifold, &isGoodOri ); + + if ( !isManifold ) + { + // set bad faces into a compute error + const char* text = "Non-manifold mesh. Only manifold mesh can be re-meshed"; + SMESH_ComputeErrorPtr error = SMESH_ComputeError::New( COMPERR_BAD_INPUT_MESH, text ); + SMESH::Controls::MultiConnection2D fun; + fun.SetMesh( myMeshDS ); + SMDS_ElemIteratorPtr fIt = myMeshDS->elementsIterator( SMDSAbs_Face ); + while ( fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + if ( fun.GetValue( f->GetID() ) > 2 ) + error->myBadElements.push_back( f ); + } + theMesh.GetSubMesh( theMesh.GetShapeToMesh() )->GetComputeError() = error; + throw SALOME_Exception( text ); + } + + // don't want to sew coincident borders + if ( !holes.empty() ) + { + // define tolerance + double tol, len, sumLen = 0, minLen = 1e100; + int nbSeg = 0; + for ( size_t i = 0; i < holes.size(); ++i ) + { + nbSeg += holes[i].size(); + SMESH_NodeXYZ p1 = holes[i][0]; + for ( size_t iP = 1; iP < holes[i].size(); ++iP ) + { + SMESH_NodeXYZ p2 = holes[i][iP]; + len = ( p1 - p2 ).Modulus(); + sumLen += len; + minLen = Min( minLen, len ); + p1 = p2; + } + } + double avgLen = sumLen / nbSeg; + if ( minLen > 1e-5 * avgLen ) + tol = 0.1 * minLen; // minLen is not degenerate + else + tol = 0.1 * avgLen; + + SMESH_MeshAlgos::CoincidentFreeBorders freeBords; + SMESH_MeshAlgos::FindCoincidentFreeBorders( *myMeshDS, tol, freeBords ); + if ( !freeBords._coincidentGroups.empty() ) + { + const char* text = "Can't re-meshed a mesh with coincident free edges"; + SMESH_ComputeErrorPtr error = SMESH_ComputeError::New( COMPERR_BAD_INPUT_MESH, text ); + for ( size_t i = 0; i < freeBords._borders.size(); ++i ) + error->myBadElements.insert( error->myBadElements.end(), + freeBords._borders[i].begin(), + freeBords._borders[i].end() ); + theMesh.GetSubMesh( theMesh.GetShapeToMesh() )->GetComputeError() = error; + throw SALOME_Exception( text ); + } + } + + // fill holes + myHole.resize( holes.size() ); + myInHolePos.resize( holes.size() ); + std::vector newFaces; + for ( size_t i = 0; i < holes.size(); ++i ) + { + newFaces.clear(); + SMESH_MeshAlgos::FillHole( holes[i], *myMeshDS, newFaces ); + + // keep data to be able to remove hole filling faces after remeshing + if ( !newFaces.empty() ) + { + myHole[i].resize( holes[i].size() ); + for ( size_t iP = 0; iP < holes[i].size(); ++iP ) + myHole[i][iP] = SMESH_NodeXYZ( holes[i][iP] ); + + myInHolePos[i] = ( SMESH_NodeXYZ( newFaces[0]->GetNode(0)) + + SMESH_NodeXYZ( newFaces[0]->GetNode(1)) + + SMESH_NodeXYZ( newFaces[0]->GetNode(2)) ) / 3.; + myCapElems.insert( myCapElems.end(), newFaces.begin(), newFaces.end() ); + // unmark to be able to remove them if meshing is canceled + // for ( size_t iF = 0; iF < newFaces.size(); ++iF ) + // newFaces[iF]->setIsMarked( false ); + } + } + // fix orientation + if ( !isGoodOri ) + { + SMDS_ElemIteratorPtr fIt = myMeshDS->elementsIterator( SMDSAbs_Face ); + while ( fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + gp_XYZ normal; + if ( SMESH_MeshAlgos::FaceNormal( f, normal )) + { + TIDSortedElemSet allFaces; + editor.Reorient2D( allFaces, normal, f ); + break; + } + } + } + } + //================================================================================ + /*! + * \brief Add hole borders to be kept in a new mesh + */ + //================================================================================ + + void HoleFiller::AddHoleBorders( Ng_STL_Geometry * ngStlGeo ) + { + for ( size_t i = 0; i < myHole.size(); ++i ) + for ( size_t iP = 1; iP < myHole[i].size(); ++iP ) + { + Ng_STL_AddEdge( ngStlGeo, + myHole[i][iP-1].ChangeData(), + myHole[i][iP-0].ChangeData() ); + } + } + //================================================================================ + /*! + * \brief Remove triangles filling the holes + */ + //================================================================================ + + HoleFiller::~HoleFiller() + { + if ( myMeshDS->NbNodes() < 3 ) + return; + + if ( !myCapElems.empty() ) // old mesh not removed; simply remove myCapElems + { + for ( size_t i = 0; i < myCapElems.size(); ++i ) + myMeshDS->RemoveFreeElement( myCapElems[i], /*sm=*/0 ); + return; + } + + bool hasOrphanNodes = true; + + const double tol = Max( 1e-3 * netgen::mparam.minh, Precision::Confusion() ); + + for ( size_t i = 0; i < myHole.size(); ++i ) + { + std::vector< gp_XYZ >& borderPnt = myHole[i]; + const gp_XYZ& inHolePos = myInHolePos[i]; + if ( borderPnt.empty() ) continue; + borderPnt.pop_back(); // first point repeated at end + + // mark all nodes located on the hole border + + // new nodeSearcher for each hole, otherwise it contains removed nodes for i > 0 + SMESHUtils::Deleter< SMESH_NodeSearcher > nodeSearcher; + if ( hasOrphanNodes ) + { + std::vector< const SMDS_MeshNode* > sharedNodes; + sharedNodes.reserve( myMeshDS->NbNodes() ); + SMDS_NodeIteratorPtr nIt = myMeshDS->nodesIterator(); + while ( nIt->more() ) + { + const SMDS_MeshNode* n = nIt->next(); + if ( n->NbInverseElements() ) + sharedNodes.push_back( n ); + } + hasOrphanNodes = ((int) sharedNodes.size() < myMeshDS->NbNodes() ); + SMDS_ElemIteratorPtr elemIt( new SMDS_NodeVectorElemIterator( sharedNodes.begin(), + sharedNodes.end() )); + nodeSearcher._obj = SMESH_MeshAlgos::GetNodeSearcher( elemIt ); + } + else + { + nodeSearcher._obj = SMESH_MeshAlgos::GetNodeSearcher( *myMeshDS ); + } + + std::vector< const SMDS_MeshElement* > edgesToRemove; + edgesToRemove.reserve( borderPnt.size() ); + + // look for a border point coincident with a node + size_t iP = 0; + SMESH_NodeXYZ bordNode1; + for ( ; iP < borderPnt.size(); ++iP ) + { + bordNode1 = nodeSearcher->FindClosestTo( borderPnt[iP] ); + if (( bordNode1 - borderPnt[iP] ).SquareModulus() < tol * tol ) + break; + } + ++iP; + bordNode1._node->setIsMarked( true ); + + // find the rest nodes located on the hole border + boost::container::flat_set< const SMDS_MeshNode* > checkedNodes; + gp_XYZ p1 = bordNode1; + for ( size_t j = 0; j < borderPnt.size()+1; ++j, iP = ( iP+1 ) % borderPnt.size() ) + { + // among nodes surrounding bordNode1 find one most close to vec12 + gp_XYZ vec12 = borderPnt[iP] - p1; + bool pntReached = false; // last found node is at iP + while ( !pntReached ) + { + const SMDS_MeshNode* bordNode = bordNode1._node; + SMDS_ElemIteratorPtr fIt = bordNode->GetInverseElementIterator( SMDSAbs_Face ); + double minArea = 1e100; + checkedNodes.clear(); + checkedNodes.insert( bordNode ); + while ( fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + for ( int iN = 0, nbN = f->NbNodes(); iN < nbN; ++iN ) + { + const SMDS_MeshNode* n = f->GetNode( iN ); + if ( !checkedNodes.insert( n ).second ) + continue; + SMESH_NodeXYZ pn = n; + gp_XYZ vecPN = pn - bordNode1; + if ( vecPN * vec12 <= 0 ) + continue; + gp_XYZ vec1N = pn - p1; + double a = vec12.CrossSquareMagnitude( vec1N ); + if ( a < minArea ) + { + bordNode = n; + minArea = a; + } + } + if ( minArea < std::numeric_limits::min() ) + break; + } + if ( bordNode == bordNode1._node ) + return; // bug in the loop above + + SMESH_NodeXYZ bordNode2 = bordNode; + gp_XYZ vec1N = bordNode2 - p1; + double u = ( vec12 * vec1N ) / vec12.SquareModulus(); // param [0,1] of bordNode on vec12 + if ( u < 1 + tol ) + { + bordNode->setIsMarked( true ); + //cout << bordNode->GetID() << " "; + + if ( const SMDS_MeshElement* edge = myMeshDS->FindEdge( bordNode1._node, bordNode )) + edgesToRemove.push_back( edge ); + else + edgesToRemove.push_back( myMeshDS->AddEdge( bordNode1._node, bordNode )); + edgesToRemove.back()->setIsMarked( true ); + + if ( minArea > std::numeric_limits::min() && + minArea / vec12.SquareModulus() > tol * tol ) + { + // node is far from the border, move it + gp_XYZ p = p1 + u * vec12; + myMeshDS->MoveNode( bordNode, p.X(), p.Y(), p.Z() ); + } + bordNode1 = bordNode2; + } + //else -- there must be another border point between bordNode1 and bordNode + pntReached = ( u > 1 - tol ); + } + p1 = borderPnt[iP]; + + } + //cout << endl << endl; + + // remove all faces starting from inHolePos + + // get a starting face + std::vector< const SMDS_MeshNode* > nodesToRemove; + std::vector< const SMDS_MeshElement* > facesToRemove; + const SMDS_MeshNode* inHoleNode = nodeSearcher->FindClosestTo( inHolePos ); + if ( inHoleNode && ! inHoleNode->isMarked() ) + { + SMDS_ElemIteratorPtr fIt = inHoleNode->GetInverseElementIterator( SMDSAbs_Face ); + while ( fIt->more() ) + facesToRemove.push_back( fIt->next() ); + } + else + { + SMESHUtils::Deleter< SMESH_ElementSearcher > faceSearcher + ( SMESH_MeshAlgos::GetElementSearcher( *myMeshDS )); + if ( const SMDS_MeshElement* f = faceSearcher->FindClosestTo( inHolePos, SMDSAbs_Face )) + facesToRemove.push_back( f ); + else + continue; + } + for ( size_t iF = 0; iF < facesToRemove.size(); ++iF ) + facesToRemove[iF]->setIsMarked( true ); + + // remove faces and nodes + TIDSortedElemSet elemSet, avoidSet; + const SMDS_MeshElement* e; + while ( !facesToRemove.empty() ) + { + const SMDS_MeshElement* inHoleFace = facesToRemove.back(); + facesToRemove.pop_back(); + + // add adjacent faces into facesToRemove + for ( int iN = 0, nbN = inHoleFace->NbNodes(); iN < nbN; ++iN ) + { + const SMDS_MeshNode* n1 = inHoleFace->GetNode( iN ); + if ( !n1->isMarked() ) + { + SMDS_ElemIteratorPtr eIt = n1->GetInverseElementIterator(); + while ( eIt->more() ) + { + e = eIt->next(); + if ( e->GetType() == SMDSAbs_Face ) + { + if ( !e->isMarked() ) + facesToRemove.push_back( e ); + e->setIsMarked( true ); + } + else if ( e->GetType() == SMDSAbs_Edge ) + { + myMeshDS->RemoveFreeElement( e, 0, /*fromGroups=*/false ); + } + } + if ( n1->NbInverseElements() == 1 ) + nodesToRemove.push_back( n1 ); + } + else + { + const SMDS_MeshNode* n2 = inHoleFace->GetNodeWrap( iN+1 ); + if (( n2->isMarked() ) && + ( !(e = myMeshDS->FindEdge( n1, n2 )) || !e->isMarked() )) // n1-n2 not hole border + { + if ( e ) // remove edge + myMeshDS->RemoveFreeElement( e, 0, /*fromGroups=*/false ); + avoidSet.clear(); + avoidSet.insert( inHoleFace ); + if (( e = SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet ))) + { + if ( !e->isMarked() ) + facesToRemove.push_back( e ); + e->setIsMarked( true ); + } + } + } + } + myMeshDS->RemoveFreeElement( inHoleFace, 0, /*fromGroups=*/false ); + + for ( size_t iN = 0; iN < nodesToRemove.size(); ++iN ) + myMeshDS->RemoveFreeNode( nodesToRemove[iN], 0, /*fromGroups=*/false ); + nodesToRemove.clear(); + } + + // remove edges from the hole border + // for ( size_t iE = 0; iE < edgesToRemove.size(); ++iE ) + // myMeshDS->RemoveFreeElement( edgesToRemove[iE], 0, /*fromGroups=*/false ); + + } // loop on holes + + return; + } // ~HoleFiller() + + } // namespace + + //============================================================================= + /*! + * Constructor + */ + //============================================================================= + -NETGENPlugin_Remesher_2D::NETGENPlugin_Remesher_2D(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_2D_Algo(hypId, studyId, gen) ++NETGENPlugin_Remesher_2D::NETGENPlugin_Remesher_2D(int hypId, SMESH_Gen* gen) ++ : SMESH_2D_Algo(hypId, gen) + { + _name = "NETGEN_Remesher_2D"; + _shapeType = (1 << TopAbs_FACE); // 1 bit /shape type + _compatibleHypothesis.push_back("NETGEN_RemesherParameters_2D"); + _requireShape = false; + + _hypothesis = 0; + } + + //============================================================================= + /*! + * Check assigned hypotheses + */ + //============================================================================= + + bool NETGENPlugin_Remesher_2D::CheckHypothesis (SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + Hypothesis_Status& theStatus) + { + _hypothesis = 0; + + // can work with no hypothesis + theStatus = SMESH_Hypothesis::HYP_OK; + + const list& hyps = + GetUsedHypothesis( theMesh, theShape, /*skipAux=*/true ); + + switch ( hyps.size() ) { + case 0: + break; + case 1: + _hypothesis = hyps.front(); + break; + default: + theStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE; + } + + return theStatus == SMESH_Hypothesis::HYP_OK; + } + + //============================================================================= + /*! + * Compute mesh on an input mesh + */ + //============================================================================= + + bool NETGENPlugin_Remesher_2D::Compute(SMESH_Mesh& theMesh, + SMESH_MesherHelper* theHelper) + { + if ( theMesh.NbFaces() == 0 ) + return !error( COMPERR_WARNING, "No faces in input mesh"); + + NETGENPlugin_Mesher mesher( &theMesh, theMesh.GetShapeToMesh(), /*isVol=*/false); + NETGENPlugin_NetgenLibWrapper ngLib; + netgen::Mesh * ngMesh = (netgen::Mesh*) ngLib._ngMesh; + Ng_STL_Geometry * ngStlGeo = Ng_STL_NewGeometry(); + netgen::STLTopology* stlTopo = (netgen::STLTopology*) ngStlGeo; + netgen::multithread.terminate = 0; + + const NETGENPlugin_RemesherHypothesis_2D* hyp = + dynamic_cast( _hypothesis ); + mesher.SetParameters( hyp );// for holeFiller + + SMESHDS_Mesh* meshDS = theMesh.GetMeshDS(); + HoleFiller holeFiller( theMesh ); + //theHelper->SetIsQuadratic( theMesh.NbFaces( ORDER_QUADRATIC )); + + // fill ngStlGeo with triangles + SMDS_ElemIteratorPtr fIt = meshDS->elementsIterator( SMDSAbs_Face ); + while ( fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + SMESH_NodeXYZ n1 = f->GetNode( 0 ); + SMESH_NodeXYZ n2 = f->GetNode( 1 ); + SMESH_NodeXYZ n3 = f->GetNode( 2 ); + Ng_STL_AddTriangle( ngStlGeo, + n1.ChangeData(), + n2.ChangeData(), + n3.ChangeData() ); + if ( f->NbNodes() > 3 ) + { + n2.Set( f->GetNode( 3 )); + Ng_STL_AddTriangle( ngStlGeo, + n1.ChangeData(), + n3.ChangeData(), + n2.ChangeData()); + } + } + // add edges + holeFiller.AddHoleBorders( ngStlGeo ); + + // init stl DS + Ng_Result ng_res = Ng_STL_InitSTLGeometry( ngStlGeo ); + if ( ng_res != NG_OK ) + { + #ifdef _DEBUG_ + holeFiller.KeepHole(); + #endif + std::string txt = "Error Initialising the STL Geometry"; + if ( !stlTopo->GetStatusText().empty() ) + txt += ". " + stlTopo->GetStatusText(); + return error( COMPERR_BAD_INPUT_MESH, txt ); + } + + Ng_Meshing_Parameters ngParams; + ng_res = Ng_STL_MakeEdges( ngStlGeo, ngLib._ngMesh, &ngParams ); + if ( ng_res != NG_OK ) + return error( "Error in Edge Meshing" ); + + // set parameters + if ( hyp ) + { + ngParams.maxh = hyp->GetMaxSize(); + ngParams.minh = hyp->GetMinSize(); + ngParams.meshsize_filename = (char*) hyp->GetMeshSizeFile().c_str(); + ngParams.quad_dominated = hyp->GetQuadAllowed(); + netgen::stlparam.yangle = hyp->GetRidgeAngle(); + mesher.SetParameters( hyp ); + } + else + { + double diagSize = Dist( stlTopo->GetBoundingBox().PMin(), stlTopo->GetBoundingBox().PMax()); + netgen::mparam.maxh = diagSize / GetGen()->GetBoundaryBoxSegmentation(); + netgen::mparam.minh = netgen::mparam.maxh; + } + + double h = netgen::mparam.maxh; + ngMesh->SetGlobalH( h ); + ngMesh->SetMinimalH( netgen::mparam.minh ); + ngMesh->SetLocalH( stlTopo->GetBoundingBox().PMin() - netgen::Vec3d(h, h, h), + stlTopo->GetBoundingBox().PMax() + netgen::Vec3d(h, h, h), + netgen::mparam.grading ); + ngMesh->LoadLocalMeshSize( ngParams.meshsize_filename ); + + netgen::OCCGeometry occgeo; + mesher.SetLocalSize( occgeo, *ngMesh ); + + // meshing + try + { + ng_res = Ng_STL_GenerateSurfaceMesh( ngStlGeo, ngLib._ngMesh, &ngParams ); + } + catch (netgen::NgException & ex) + { + if ( netgen::multithread.terminate ) + return false; + } + if ( ng_res != NG_OK ) + return error( "Error in Surface Meshing" ); + + int nbN = ngMesh->GetNP(); + int nbE = ngMesh->GetNSeg(); + int nbF = ngMesh->GetNSE(); + if ( nbF == 0 ) + return error( "Error in Surface Meshing" ); + + // remove existing mesh + holeFiller.ClearCapElements(); + SMDS_ElemIteratorPtr eIt = meshDS->elementsIterator(); + while ( eIt->more() ) + meshDS->RemoveFreeElement( eIt->next(), /*sm=*/0 ); + SMDS_NodeIteratorPtr nIt = meshDS->nodesIterator(); + while ( nIt->more() ) + meshDS->RemoveFreeNode( nIt->next(), /*sm=*/0 ); + + // retrieve new mesh + + // add nodes + std::vector< const SMDS_MeshNode* > newNodes( nbN+1 ); + for ( int i = 1; i <= nbN; ++i ) + { + const netgen::MeshPoint& p = ngMesh->Point(i); + newNodes[i] = meshDS->AddNode( p(0),p(1),p(2) ); + } + + // add edges + std::vector nodes(4); + for ( int i = 1; i <= nbE; ++i ) + { + const netgen::Segment& seg = ngMesh->LineSegment(i); + nodes.clear(); + for ( int j = 0; j < 2; ++j ) + { + size_t pind = seg.pnums[j]; + if ( pind > 0 && pind < newNodes.size() ) + nodes.push_back( newNodes[ pind ]); + else + break; + } + if ( nodes.size() == 2 && !meshDS->FindEdge( nodes[0], nodes[1] )) + meshDS->AddEdge( nodes[0], nodes[1] ); + } + + // add faces + for ( int i = 1; i <= nbF; ++i ) + { + const netgen::Element2d& elem = ngMesh->SurfaceElement(i); + nodes.clear(); + for ( int j = 1; j <= elem.GetNP(); ++j ) + { + size_t pind = elem.PNum(j); + if ( pind > 0 && pind < newNodes.size() ) + nodes.push_back( newNodes[ pind ]); + else + break; + } + switch( nodes.size() ) + { + case 3: meshDS->AddFace( nodes[0], nodes[1], nodes[2] ); break; + case 4: meshDS->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break; + } + } + + // as we don't assign the new triangles to a shape (the pseudo-shape), + // to avoid their removal at hypothesis modification, + // we mark the shape as always computed to avoid the error messages + // that no elements assigned to the shape + theMesh.GetSubMesh( theHelper->GetSubShape() )->SetIsAlwaysComputed( true ); + + return true; + } + + //============================================================================= + /*! + * Do not compute mesh on geometry + */ + //============================================================================= + + bool NETGENPlugin_Remesher_2D::Compute(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape) + { + return false; + } + + //============================================================================= + /*! + * Terminate Compute() + */ + //============================================================================= + + void NETGENPlugin_Remesher_2D::CancelCompute() + { + SMESH_Algo::CancelCompute(); + netgen::multithread.terminate = 1; + } + + //================================================================================ + /*! + * \brief Return progress of Compute() [0.,1] + */ + //================================================================================ + + double NETGENPlugin_Remesher_2D::GetProgress() const + { + return netgen::multithread.percent / 100.; + } + + //============================================================================= + /*! + * + */ + //============================================================================= + + bool NETGENPlugin_Remesher_2D::Evaluate(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + MapShapeNbElems& aResMap) + { + return false; + } diff --cc src/NETGENPlugin/NETGENPlugin_Remesher_2D.hxx index 0000000,be9a161..3a0ef62 mode 000000,100644..100644 --- a/src/NETGENPlugin/NETGENPlugin_Remesher_2D.hxx +++ b/src/NETGENPlugin/NETGENPlugin_Remesher_2D.hxx @@@ -1,0 -1,62 +1,62 @@@ + // Copyright (C) 2007-2016 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 + // + // 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, 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 + // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + // Lesser General Public License for more details. + // + // You should have received a copy of the GNU Lesser General Public + // License along with this library; if not, write to the Free Software + // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + // + // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com + // + // File : NETGENPlugin_Remesher_2D.hxx + // Created : Thu Sep 21 16:48:46 2017 + // Author : Edward AGAPOV (eap) + + + #ifndef __NETGENPlugin_Remesher_2D_HXX__ + #define __NETGENPlugin_Remesher_2D_HXX__ + + #include "NETGENPlugin_Defs.hxx" + + #include "SMESH_Algo.hxx" + #include "SMESH_Mesh.hxx" + + class NETGENPLUGIN_EXPORT NETGENPlugin_Remesher_2D: public SMESH_2D_Algo + { + public: - NETGENPlugin_Remesher_2D(int hypId, int studyId, SMESH_Gen* gen); ++ NETGENPlugin_Remesher_2D(int hypId, SMESH_Gen* gen); + + virtual bool CheckHypothesis(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + SMESH_Hypothesis::Hypothesis_Status& theStatus); + + virtual bool Compute(SMESH_Mesh & theMesh, SMESH_MesherHelper* theHelper); + + virtual bool Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape); + + virtual void CancelCompute(); + + virtual double GetProgress() const; + + + virtual bool Evaluate(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + MapShapeNbElems& theResMap); + + protected: + + const SMESHDS_Hypothesis* _hypothesis; + }; + + #endif