From d01b6f371fa48d6a0d000e2b4ef389b605c035b6 Mon Sep 17 00:00:00 2001 From: eap Date: Thu, 19 Oct 2017 19:53:43 +0300 Subject: [PATCH] refs #254: 7.5.5. Mesh generation for semi-analytical boundaries Add NETGEN Remesher --- .../NETGENPLUGIN/images/netgen2d_remesher.png | 0 doc/salome/gui/NETGENPLUGIN/input/index.doc | 4 + .../NETGENPLUGIN/input/netgen_2d_3d_hypo.doc | 15 +- idl/NETGENPlugin_Algorithm.idl | 26 +- resources/NETGENPlugin.xml | 23 + src/GUI/NETGENPluginGUI.cxx | 9 +- src/GUI/NETGENPluginGUI_HypothesisCreator.cxx | 344 +++++---- src/GUI/NETGENPluginGUI_HypothesisCreator.h | 5 +- src/GUI/NETGENPlugin_msg_en.ts | 8 + src/NETGENPlugin/CMakeLists.txt | 2 + src/NETGENPlugin/NETGENPluginBuilder.py | 24 +- src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx | 6 +- .../NETGENPlugin_Hypothesis_2D.cxx | 123 ++-- .../NETGENPlugin_Hypothesis_2D.hxx | 23 + .../NETGENPlugin_Hypothesis_2D_i.cxx | 104 ++- .../NETGENPlugin_Hypothesis_2D_i.hxx | 23 + src/NETGENPlugin/NETGENPlugin_Mesher.cxx | 8 +- src/NETGENPlugin/NETGENPlugin_Mesher.hxx | 2 +- src/NETGENPlugin/NETGENPlugin_NETGEN_2D_i.cxx | 41 +- src/NETGENPlugin/NETGENPlugin_NETGEN_2D_i.hxx | 21 +- src/NETGENPlugin/NETGENPlugin_Remesher_2D.cxx | 692 ++++++++++++++++++ src/NETGENPlugin/NETGENPlugin_Remesher_2D.hxx | 62 ++ src/NETGENPlugin/NETGENPlugin_i.cxx | 4 + 23 files changed, 1311 insertions(+), 258 deletions(-) create mode 100644 doc/salome/gui/NETGENPLUGIN/images/netgen2d_remesher.png create mode 100644 src/NETGENPlugin/NETGENPlugin_Remesher_2D.cxx create mode 100644 src/NETGENPlugin/NETGENPlugin_Remesher_2D.hxx diff --git a/doc/salome/gui/NETGENPLUGIN/images/netgen2d_remesher.png b/doc/salome/gui/NETGENPLUGIN/images/netgen2d_remesher.png new file mode 100644 index 0000000..e69de29 diff --git a/doc/salome/gui/NETGENPLUGIN/input/index.doc b/doc/salome/gui/NETGENPLUGIN/input/index.doc index f2d23d4..c255103 100644 --- a/doc/salome/gui/NETGENPLUGIN/input/index.doc +++ b/doc/salome/gui/NETGENPLUGIN/input/index.doc @@ -9,6 +9,10 @@ - Solids are split into tetrahedral elements. Pyramids are constructed as a transition from quadrangles to tetrahedra. - Generating 3D meshes from 2D meshes, working without geometrical objects. +- Generating 2D meshes from 2D meshes, working without geometrical objects. + +When working without geometrical objects, Negten requires that the +input mesh to be a manifold shell. To manage parameters of the NETGENPLUGIN use \subpage netgen_2d_3d_hypo_page and \subpage additional_hypo_page. diff --git a/doc/salome/gui/NETGENPLUGIN/input/netgen_2d_3d_hypo.doc b/doc/salome/gui/NETGENPLUGIN/input/netgen_2d_3d_hypo.doc index 1113607..30ae1d9 100644 --- a/doc/salome/gui/NETGENPLUGIN/input/netgen_2d_3d_hypo.doc +++ b/doc/salome/gui/NETGENPLUGIN/input/netgen_2d_3d_hypo.doc @@ -17,6 +17,10 @@ meshing 2D objects). \image html netgen2d3d_only.png
Dialog boxes of NETGEN 2D and NETGEN 3D algorithms
+
+\image html netgen2d_remesher.png +
Hypothesis dialog box of NETGEN 2D remesher algorithms
+ - Name - allows to define the name for the algorithm (NETGEN 2D (or 3D) Parameters by default). @@ -61,6 +65,9 @@ process is rather time consuming comparing to creation of initial mesh. - Fuse Coincident Nodes on Edges and Vertices - allows merging mesh nodes on vertices and edges which are geometrically coincident but are topologically different. +- Ridge angle - allows to define minimum angle in degrees between +normals of adjacent triangles at which the remesher (Netgen 2D working +w/o geometry) considers the edge between these triangles as a feature edge. \image html netgen3d_local_size.png @@ -76,7 +83,9 @@ can be changed. - Mesh-size File - opens a dialog to select a file defining size of elements. The file includes two obligatory sections. The first section defines the size at points. The second section defines the -size along lines. Let's consider the following sample size file. +size along lines. Sizes defined in the file are trimmed between Min +Size and Max Size bounds. Let's consider the following +sample size file. \code 2 92.5 92.5 92.5 0.05 @@ -96,6 +105,7 @@ section.
Sizes defined in the file are trimmed between Min Size and Max Size bounds. + \image html netgen2d3d_simple.png NETGEN 2D simple parameters and NETGEN 3D simple @@ -133,6 +143,7 @@ close edges influence each other. - The local size of segments influences the size of close triangles. - The order of elements and their size in the 1D mesh generated by NETGEN differ from those in the 1D mesh generated by Regular_1D -algorithm, resulting in different 2D and 3D meshes. +algorithm, which results in different 2D and 3D meshes at the same 1D +input parameters. */ diff --git a/idl/NETGENPlugin_Algorithm.idl b/idl/NETGENPlugin_Algorithm.idl index 71b84f5..8ca0681 100644 --- a/idl/NETGENPlugin_Algorithm.idl +++ b/idl/NETGENPlugin_Algorithm.idl @@ -66,6 +66,14 @@ module NETGENPlugin { }; + /*! + * NETGENPlugin_Remesher_2D: interface of "NETGEN Remesher" algorithm, + * generating 2D elements basing on an existing 2D mesh + */ + interface NETGENPlugin_Remesher_2D : SMESH::SMESH_2D_Algo + { + }; + /*! * NETGENPlugin_Hypothesis: interface of "NETGEN parameters" hypothesis */ @@ -92,14 +100,14 @@ module NETGENPlugin void SetNbSegPerEdge(in double value); double GetNbSegPerEdge(); + void SetNbSegPerRadius(in double value); + double GetNbSegPerRadius(); + void SetChordalErrorEnabled(in boolean value); boolean GetChordalErrorEnabled(); void SetChordalError(in double value); double GetChordalError(); - void SetNbSegPerRadius(in double value); - double GetNbSegPerRadius(); - void SetQuadAllowed(in boolean value); boolean GetQuadAllowed(); @@ -141,6 +149,18 @@ module NETGENPlugin { }; + /*! + * interface of "NETGEN Remesher parameters" hypothesis used by NETGENPlugin_Remesher_2D algoritm + */ + interface NETGENPlugin_RemesherHypothesis_2D : NETGENPlugin_Hypothesis_2D + { + /*! + * \brief Set/get ridge angle + */ + void SetRidgeAngle(in double angle ); + double GetRidgeAngle(); + }; + /*! * NETGENPlugin_Hypothesis: interface of "NETGEN 2D simple parameters" hypothesis */ diff --git a/resources/NETGENPlugin.xml b/resources/NETGENPlugin.xml index 9e0c77e..fc93a25 100644 --- a/resources/NETGENPlugin.xml +++ b/resources/NETGENPlugin.xml @@ -45,6 +45,7 @@ + + + + + + + + + + NETGEN_Remesher_2D=Triangle(algo=smeshBuilder.NETGEN) + NETGEN_RemesherParameters_2D=Parameters() + + + diff --git a/src/GUI/NETGENPluginGUI.cxx b/src/GUI/NETGENPluginGUI.cxx index 51b876b..34f9ab8 100755 --- a/src/GUI/NETGENPluginGUI.cxx +++ b/src/GUI/NETGENPluginGUI.cxx @@ -41,10 +41,11 @@ extern "C" SMESHGUI_GenericHypothesisCreator* GetHypothesisCreator( const QString& aHypType ) { SMESHGUI_GenericHypothesisCreator* aCreator = NULL; - if( aHypType=="NETGEN_Parameters_2D" || // 1D-2D - aHypType=="NETGEN_Parameters" || // 1D-2D-3D - aHypType=="NETGEN_Parameters_2D_ONLY" || // 2D - aHypType=="NETGEN_Parameters_3D" ) // 3D + if( aHypType=="NETGEN_Parameters_2D" || // 1D-2D + aHypType=="NETGEN_Parameters" || // 1D-2D-3D + aHypType=="NETGEN_Parameters_2D_ONLY" || // 2D + aHypType=="NETGEN_Parameters_3D" || // 3D + aHypType=="NETGEN_RemesherParameters_2D" ) // 2D { aCreator = new NETGENPluginGUI_HypothesisCreator( aHypType ); } diff --git a/src/GUI/NETGENPluginGUI_HypothesisCreator.cxx b/src/GUI/NETGENPluginGUI_HypothesisCreator.cxx index e207e26..bbb79bb 100644 --- a/src/GUI/NETGENPluginGUI_HypothesisCreator.cxx +++ b/src/GUI/NETGENPluginGUI_HypothesisCreator.cxx @@ -92,9 +92,11 @@ NETGENPluginGUI_HypothesisCreator::NETGENPluginGUI_HypothesisCreator( const QStr { myGeomSelectionTools = NULL; myLocalSizeMap.clear(); - myIs2D = ( theHypType.startsWith("NETGEN_Parameters_2D")); + myIs2D = ( theHypType.startsWith("NETGEN_Parameters_2D") || + theHypType == "NETGEN_RemesherParameters_2D"); myIsONLY = ( theHypType == "NETGEN_Parameters_2D_ONLY" || - theHypType == "NETGEN_Parameters_3D"); + theHypType == "NETGEN_Parameters_3D" || + theHypType == "NETGEN_RemesherParameters_2D"); } NETGENPluginGUI_HypothesisCreator::~NETGENPluginGUI_HypothesisCreator() @@ -116,6 +118,8 @@ bool NETGENPluginGUI_HypothesisCreator::checkParams(QString& msg) const res = myNbSegPerEdge->isValid(msg,true) && res; if ( myNbSegPerRadius ) res = myNbSegPerRadius->isValid(msg,true) && res; + if ( myRidgeAngle ) + res = myRidgeAngle->isValid(msg,true) && res; if ( !res ) // -- issue 0021364: Dump of netgen parameters has duplicate lines storeParamsToHypo( data_old ); @@ -125,6 +129,8 @@ bool NETGENPluginGUI_HypothesisCreator::checkParams(QString& msg) const QFrame* NETGENPluginGUI_HypothesisCreator::buildFrame() { + const bool isRemesher = ( hypType() == "NETGEN_RemesherParameters_2D" ); + QFrame* fr = new QFrame( 0 ); fr->setObjectName( "myframe" ); QVBoxLayout* lay = new QVBoxLayout( fr ); @@ -210,7 +216,7 @@ QFrame* NETGENPluginGUI_HypothesisCreator::buildFrame() myChordalErrorEnabled = 0; myChordalError = 0; - if ( myIs2D || !myIsONLY ) + if (( myIs2D && !isRemesher ) || !myIsONLY ) { myChordalErrorEnabled = new QCheckBox( tr( "NETGEN_CHORDAL_ERROR" ), GroupC1 ); aGroupLayout->addWidget( myChordalErrorEnabled, row, 0 ); @@ -221,8 +227,18 @@ QFrame* NETGENPluginGUI_HypothesisCreator::buildFrame() row++; } + myRidgeAngle = 0; + if ( isRemesher ) + { + aGroupLayout->addWidget( new QLabel( tr( "NETGEN_RIDGE_ANGLE" ), GroupC1 ), row, 0 ); + myRidgeAngle = new SMESHGUI_SpinBox( GroupC1 ); + myRidgeAngle->RangeStepAndValidator( 0, 90, 10, "angle_precision" ); + aGroupLayout->addWidget( myRidgeAngle, row, 1 ); + row++; + } + mySurfaceCurvature = 0; - if ( myIs2D || !myIsONLY ) + if (( myIs2D && !isRemesher ) || !myIsONLY ) { mySurfaceCurvature = new QCheckBox( tr( "NETGEN_SURFACE_CURVATURE" ), GroupC1 ); aGroupLayout->addWidget( mySurfaceCurvature, row, 0, 1, 2 ); @@ -238,12 +254,16 @@ QFrame* NETGENPluginGUI_HypothesisCreator::buildFrame() row++; } - myOptimize = new QCheckBox( tr( "NETGEN_OPTIMIZE" ), GroupC1 ); - aGroupLayout->addWidget( myOptimize, row, 0, 1, 2 ); - row++; + myOptimize = 0; + if ( !isRemesher ) + { + myOptimize = new QCheckBox( tr( "NETGEN_OPTIMIZE" ), GroupC1 ); + aGroupLayout->addWidget( myOptimize, row, 0, 1, 2 ); + row++; + } myFuseEdges = 0; - if (!myIsONLY) + if ( !myIsONLY ) { myFuseEdges = new QCheckBox( tr( "NETGEN_FUSE_EDGES" ), GroupC1 ); aGroupLayout->addWidget( myFuseEdges, row, 0, 1, 2 ); @@ -359,6 +379,13 @@ void NETGENPluginGUI_HypothesisCreator::retrieveParams() const myChordalError->setText( data.myChordalErrorVar ); myChordalError->setEnabled( myChordalErrorEnabled->isChecked() ); } + if ( myRidgeAngle ) + { + if ( data.myRidgeAngleVar.isEmpty() ) + myRidgeAngle->setValue( data.myRidgeAngle ); + else + myRidgeAngle->setText( data.myRidgeAngleVar ); + } if (myAllowQuadrangles) myAllowQuadrangles->setChecked( data.myAllowQuadrangles ); @@ -403,26 +430,26 @@ QString NETGENPluginGUI_HypothesisCreator::storeParams() const readParamsFromWidgets( data ); storeParamsToHypo( data ); - QString valStr = tr("NETGEN_MAX_SIZE") + " = " + QString::number( data.myMaxSize ) + "; "; - valStr += tr("NETGEN_MIN_SIZE") + " = " + QString::number( data.myMinSize ) + "; "; - if ( data.mySecondOrder ) - valStr += tr("NETGEN_SECOND_ORDER") + "; "; - if ( data.myOptimize ) - valStr += tr("NETGEN_OPTIMIZE") + "; "; - valStr += myFineness->currentText() + "(" + QString::number( data.myGrowthRate ) + ", " + - QString::number( data.myNbSegPerEdge ) + ", " + - QString::number( data.myNbSegPerRadius ) + ")"; + // QString valStr = tr("NETGEN_MAX_SIZE") + " = " + QString::number( data.myMaxSize ) + "; "; + // valStr += tr("NETGEN_MIN_SIZE") + " = " + QString::number( data.myMinSize ) + "; "; + // if ( data.mySecondOrder ) + // valStr += tr("NETGEN_SECOND_ORDER") + "; "; + // if ( data.myOptimize ) + // valStr += tr("NETGEN_OPTIMIZE") + "; "; + // valStr += myFineness->currentText() + "(" + QString::number( data.myGrowthRate ) + ", " + + // QString::number( data.myNbSegPerEdge ) + ", " + + // QString::number( data.myNbSegPerRadius ) + ")"; - if ( myIs2D && data.myAllowQuadrangles ) - valStr += "; " + tr("NETGEN_ALLOW_QUADRANGLES"); + // if ( myIs2D && data.myAllowQuadrangles ) + // valStr += "; " + tr("NETGEN_ALLOW_QUADRANGLES"); - if ( data.mySurfaceCurvature ) - valStr += "; " + tr("NETGEN_SURFACE_CURVATURE"); + // if ( data.mySurfaceCurvature ) + // valStr += "; " + tr("NETGEN_SURFACE_CURVATURE"); - if ( data.myFuseEdges ) - valStr += "; " + tr("NETGEN_FUSE_EDGES"); + // if ( data.myFuseEdges ) + // valStr += "; " + tr("NETGEN_FUSE_EDGES"); - return valStr; + return QString(); } bool NETGENPluginGUI_HypothesisCreator::readParamsFromHypo( NetgenHypothesisData& h_data ) const @@ -455,12 +482,20 @@ bool NETGENPluginGUI_HypothesisCreator::readParamsFromHypo( NetgenHypothesisData //if ( myIs2D ) { - NETGENPlugin::NETGENPlugin_Hypothesis_var h = - NETGENPlugin::NETGENPlugin_Hypothesis::_narrow( initParamsHypothesis() ); + // NETGENPlugin::NETGENPlugin_Hypothesis_var h = + // NETGENPlugin::NETGENPlugin_Hypothesis::_narrow( initParamsHypothesis() ); if ( !h->_is_nil() ) h_data.myAllowQuadrangles = h->GetQuadAllowed(); } + if ( myIs2D ) + { + NETGENPlugin::NETGENPlugin_RemesherHypothesis_2D_var rh = + NETGENPlugin::NETGENPlugin_RemesherHypothesis_2D::_narrow( h ); + + if ( !rh->_is_nil() ) + h_data.myRidgeAngle = rh->GetRidgeAngle(); + } NETGENPluginGUI_HypothesisCreator* that = (NETGENPluginGUI_HypothesisCreator*)this; NETGENPlugin::string_array_var myEntries = h->GetLocalSizeEntries(); @@ -496,8 +531,10 @@ bool NETGENPluginGUI_HypothesisCreator::storeParamsToHypo( const NetgenHypothesi SMESH::SetName( SMESH::FindSObject( h ), h_data.myName.toLatin1().data() ); h->SetVarParameter( h_data.myMaxSizeVar.toLatin1().constData(), "SetMaxSize"); h->SetMaxSize ( h_data.myMaxSize ); - h->SetSecondOrder ( h_data.mySecondOrder ); - h->SetOptimize ( h_data.myOptimize ); + if ( mySecondOrder ) + h->SetSecondOrder ( h_data.mySecondOrder ); + if ( myOptimize ) + h->SetOptimize ( h_data.myOptimize ); int fineness = h_data.myFineness; h->SetFineness ( fineness ); @@ -505,34 +542,53 @@ bool NETGENPluginGUI_HypothesisCreator::storeParamsToHypo( const NetgenHypothesi { h->SetVarParameter ( h_data.myGrowthRateVar.toLatin1().constData(), "SetGrowthRate"); h->SetGrowthRate ( h_data.myGrowthRate ); - h->SetVarParameter ( h_data.myNbSegPerEdgeVar.toLatin1().constData(), "SetNbSegPerEdge"); - h->SetNbSegPerEdge ( h_data.myNbSegPerEdge ); - h->SetVarParameter ( h_data.myNbSegPerRadiusVar.toLatin1().constData(), "SetNbSegPerRadius"); - h->SetNbSegPerRadius( h_data.myNbSegPerRadius ); + if ( myNbSegPerEdge ) + { + h->SetVarParameter ( h_data.myNbSegPerEdgeVar.toLatin1().constData(), "SetNbSegPerEdge"); + h->SetNbSegPerEdge ( h_data.myNbSegPerEdge ); + } + if ( myNbSegPerRadius ) + { + h->SetVarParameter ( h_data.myNbSegPerRadiusVar.toLatin1().constData(), "SetNbSegPerRadius"); + h->SetNbSegPerRadius( h_data.myNbSegPerRadius ); + } + } + if ( myChordalError ) + { + h->SetVarParameter ( h_data.myChordalErrorVar.toLatin1().constData(), "SetChordalError"); + h->SetChordalError ( h_data.myChordalError ); + h->SetChordalErrorEnabled( h_data.myChordalErrorEnabled ); } - h->SetVarParameter ( h_data.myChordalErrorVar.toLatin1().constData(), "SetChordalError"); - h->SetChordalError ( h_data.myChordalError ); - h->SetChordalErrorEnabled( h_data.myChordalErrorEnabled ); h->SetVarParameter ( h_data.myMinSizeVar.toLatin1().constData(), "SetMinSize"); h->SetMinSize ( h_data.myMinSize ); - h->SetUseSurfaceCurvature( h_data.mySurfaceCurvature ); - h->SetFuseEdges ( h_data.myFuseEdges ); + if ( mySurfaceCurvature ) + h->SetUseSurfaceCurvature( h_data.mySurfaceCurvature ); + if ( myFuseEdges ) + h->SetFuseEdges ( h_data.myFuseEdges ); h->SetMeshSizeFile ( h_data.myMeshSizeFile.toUtf8().constData() ); //if ( myIs2D ) { // NETGENPlugin::NETGENPlugin_Hypothesis_2D_var h_2d = // NETGENPlugin::NETGENPlugin_Hypothesis_2D::_narrow( h ); - // if ( !h_2d->_is_nil() ) // h_2d->SetQuadAllowed( h_data.myAllowQuadrangles ); - h->SetQuadAllowed( h_data.myAllowQuadrangles ); + if ( myAllowQuadrangles ) + h->SetQuadAllowed( h_data.myAllowQuadrangles ); } - - QMapIterator i(myLocalSizeMap); - while (i.hasNext()) { - i.next(); - const QString entry = i.key(); + if ( myIs2D ) + { + NETGENPlugin::NETGENPlugin_RemesherHypothesis_2D_var rh = + NETGENPlugin::NETGENPlugin_RemesherHypothesis_2D::_narrow( h ); + if ( !rh->_is_nil() ) + { + rh->SetVarParameter( h_data.myRidgeAngleVar.toLatin1().constData(), "SetRidgeAngle"); + rh->SetRidgeAngle ( h_data.myRidgeAngle ); + } + } + for ( QMapIterator i(myLocalSizeMap); i.hasNext(); i.next() ) + { + const QString entry = i.key(); const QString localSize = i.value(); if (localSize == "__TO_DELETE__") { @@ -540,10 +596,7 @@ bool NETGENPluginGUI_HypothesisCreator::storeParamsToHypo( const NetgenHypothesi } else { - std::istringstream tmp(localSize.toLatin1().constData()); - double val; - tmp >> val; - h->SetLocalSizeOnEntry(entry.toLatin1().constData(), val); + h->SetLocalSizeOnEntry(entry.toLatin1().constData(), localSize.toDouble()); } } } @@ -584,6 +637,11 @@ bool NETGENPluginGUI_HypothesisCreator::readParamsFromWidgets( NetgenHypothesisD h_data.myChordalError = myChordalError->value(); h_data.myChordalErrorEnabled = myChordalError->isEnabled(); } + if ( myRidgeAngle ) + { + h_data.myRidgeAngleVar = myRidgeAngle->text(); + h_data.myRidgeAngle = myRidgeAngle->value(); + } if ( myAllowQuadrangles ) h_data.myAllowQuadrangles = myAllowQuadrangles->isChecked(); @@ -634,7 +692,7 @@ void NETGENPluginGUI_HypothesisCreator::onSurfaceCurvatureChanged() void NETGENPluginGUI_HypothesisCreator::onFinenessChanged() { bool isCustom = (myFineness->currentIndex() == UserDefined); - + myGrowthRate->setEnabled(isCustom); if ( myNbSegPerEdge ) myNbSegPerEdge->setEnabled(isCustom); @@ -642,45 +700,45 @@ void NETGENPluginGUI_HypothesisCreator::onFinenessChanged() myNbSegPerRadius->setEnabled(isCustom); if (!isCustom) + { + double aGrowthRate, aNbSegPerEdge, aNbSegPerRadius; + + switch ( myFineness->currentIndex() ) { - double aGrowthRate, aNbSegPerEdge, aNbSegPerRadius; - - switch ( myFineness->currentIndex() ) - { - case VeryCoarse: - aGrowthRate = 0.7; - aNbSegPerEdge = 0.3; - aNbSegPerRadius = 1; - break; - case Coarse: - aGrowthRate = 0.5; - aNbSegPerEdge = 0.5; - aNbSegPerRadius = 1.5; - break; - case Fine: - aGrowthRate = 0.2; - aNbSegPerEdge = 2; - aNbSegPerRadius = 3; - break; - case VeryFine: - aGrowthRate = 0.1; - aNbSegPerEdge = 3; - aNbSegPerRadius = 5; - break; - case Moderate: - default: - aGrowthRate = 0.3; - aNbSegPerEdge = 1; - aNbSegPerRadius = 2; - break; - } - - myGrowthRate->setValue( aGrowthRate ); - if ( myNbSegPerEdge ) - myNbSegPerEdge->setValue( aNbSegPerEdge ); - if ( myNbSegPerRadius ) - myNbSegPerRadius->setValue( aNbSegPerRadius ); + case VeryCoarse: + aGrowthRate = 0.7; + aNbSegPerEdge = 0.3; + aNbSegPerRadius = 1; + break; + case Coarse: + aGrowthRate = 0.5; + aNbSegPerEdge = 0.5; + aNbSegPerRadius = 1.5; + break; + case Fine: + aGrowthRate = 0.2; + aNbSegPerEdge = 2; + aNbSegPerRadius = 3; + break; + case VeryFine: + aGrowthRate = 0.1; + aNbSegPerEdge = 3; + aNbSegPerRadius = 5; + break; + case Moderate: + default: + aGrowthRate = 0.3; + aNbSegPerEdge = 1; + aNbSegPerRadius = 2; + break; } + + myGrowthRate->setValue( aGrowthRate ); + if ( myNbSegPerEdge ) + myNbSegPerEdge->setValue( aNbSegPerEdge ); + if ( myNbSegPerRadius ) + myNbSegPerRadius->setValue( aNbSegPerRadius ); + } } void NETGENPluginGUI_HypothesisCreator::onAddLocalSizeOnVertex() @@ -712,54 +770,54 @@ void NETGENPluginGUI_HypothesisCreator::addLocalSizeOnShape(TopAbs_ShapeEnum typ mySel->selectedObjects(ListSelectedObjects, NULL, false ); SALOME_ListIteratorOfListIO Object_It(ListSelectedObjects); for ( ; Object_It.More() ; Object_It.Next()) + { + Handle(SALOME_InteractiveObject) anObject = Object_It.Value(); + std::string entry, shapeName; + entry = geomSelectionTools->getEntryOfObject(anObject); + shapeName = anObject->getName(); + TopAbs_ShapeEnum shapeType; + shapeType = geomSelectionTools->entryToShapeType(entry); + if (shapeType == TopAbs_SHAPE) { - Handle(SALOME_InteractiveObject) anObject = Object_It.Value(); - std::string entry, shapeName; - entry = geomSelectionTools->getEntryOfObject(anObject); - shapeName = anObject->getName(); - TopAbs_ShapeEnum shapeType; - shapeType = geomSelectionTools->entryToShapeType(entry); - if (shapeType == TopAbs_SHAPE) - { - // E.A. if shapeType == TopAbs_SHAPE, it is NOT a TopoDS_Shape !!! - continue; - } - // -- - if(shapeType != typeShapeAsked) - { - continue; - } - // -- - myLocalSizeTable->setFocus(); - QString shapeEntry; - shapeEntry = QString::fromStdString(entry); - if (myLocalSizeMap.contains(shapeEntry)) - { - if (myLocalSizeMap[shapeEntry] != "__TO_DELETE__") - { - continue; - } - } - double phySize = h->GetMaxSize(); - std::ostringstream oss; - oss << phySize; - QString localSize; - localSize = QString::fromStdString(oss.str()); - // -- - int row = myLocalSizeTable->rowCount() ; - myLocalSizeTable->setRowCount(row+1); - myLocalSizeTable->setItem(row, LSZ_ENTRY_COLUMN, new QTableWidgetItem(shapeEntry)); - myLocalSizeTable->item(row, LSZ_ENTRY_COLUMN )->setFlags(0); - myLocalSizeTable->setItem(row, LSZ_NAME_COLUMN, new QTableWidgetItem(QString::fromStdString(shapeName))); - myLocalSizeTable->item(row, LSZ_NAME_COLUMN )->setFlags(0); - myLocalSizeTable->setItem(row, LSZ_LOCALSIZE_COLUMN, new QTableWidgetItem(localSize)); - myLocalSizeTable->item(row, LSZ_LOCALSIZE_COLUMN )->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEditable|Qt::ItemIsEnabled); - myLocalSizeTable->resizeColumnToContents(LSZ_NAME_COLUMN); - myLocalSizeTable->resizeColumnToContents(LSZ_LOCALSIZE_COLUMN); - myLocalSizeTable->clearSelection(); - myLocalSizeTable->scrollToItem( myLocalSizeTable->item( row, LSZ_LOCALSIZE_COLUMN ) ); - // -- + // E.A. if shapeType == TopAbs_SHAPE, it is NOT a TopoDS_Shape !!! + continue; + } + // -- + if(shapeType != typeShapeAsked) + { + continue; } + // -- + myLocalSizeTable->setFocus(); + QString shapeEntry; + shapeEntry = QString::fromStdString(entry); + if (myLocalSizeMap.contains(shapeEntry)) + { + if (myLocalSizeMap[shapeEntry] != "__TO_DELETE__") + { + continue; + } + } + double phySize = h->GetMaxSize(); + std::ostringstream oss; + oss << phySize; + QString localSize; + localSize = QString::fromStdString(oss.str()); + // -- + int row = myLocalSizeTable->rowCount() ; + myLocalSizeTable->setRowCount(row+1); + myLocalSizeTable->setItem(row, LSZ_ENTRY_COLUMN, new QTableWidgetItem(shapeEntry)); + myLocalSizeTable->item(row, LSZ_ENTRY_COLUMN )->setFlags(0); + myLocalSizeTable->setItem(row, LSZ_NAME_COLUMN, new QTableWidgetItem(QString::fromStdString(shapeName))); + myLocalSizeTable->item(row, LSZ_NAME_COLUMN )->setFlags(0); + myLocalSizeTable->setItem(row, LSZ_LOCALSIZE_COLUMN, new QTableWidgetItem(localSize)); + myLocalSizeTable->item(row, LSZ_LOCALSIZE_COLUMN )->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEditable|Qt::ItemIsEnabled); + myLocalSizeTable->resizeColumnToContents(LSZ_NAME_COLUMN); + myLocalSizeTable->resizeColumnToContents(LSZ_LOCALSIZE_COLUMN); + myLocalSizeTable->clearSelection(); + myLocalSizeTable->scrollToItem( myLocalSizeTable->item( row, LSZ_LOCALSIZE_COLUMN ) ); + // -- + } } void NETGENPluginGUI_HypothesisCreator::onRemoveLocalSizeOnShape() @@ -777,15 +835,15 @@ void NETGENPluginGUI_HypothesisCreator::onRemoveLocalSizeOnShape() QListIterator it( selectedRows ); it.toBack(); while (it.hasPrevious()) + { + row = it.previous(); + QString entry = myLocalSizeTable->item(row,LSZ_ENTRY_COLUMN)->text(); + if (myLocalSizeMap.contains(entry)) { - row = it.previous(); - QString entry = myLocalSizeTable->item(row,LSZ_ENTRY_COLUMN)->text(); - if (myLocalSizeMap.contains(entry)) - { - myLocalSizeMap[entry] = "__TO_DELETE__"; - } - myLocalSizeTable->removeRow(row ); + myLocalSizeMap[entry] = "__TO_DELETE__"; } + myLocalSizeTable->removeRow(row ); + } myLocalSizeTable->resizeColumnToContents(LSZ_NAME_COLUMN); myLocalSizeTable->resizeColumnToContents(LSZ_LOCALSIZE_COLUMN); } @@ -819,18 +877,20 @@ GeomSelectionTools* NETGENPluginGUI_HypothesisCreator::getGeomSelectionTools() QString NETGENPluginGUI_HypothesisCreator::caption() const { - return tr( QString( "NETGEN_%1_TITLE" ).arg(myIs2D?QString("2D"):QString("3D")).toLatin1().data() ); + return tr( myIs2D ? "NETGEN_2D_TITLE" : "NETGEN_3D_TITLE"); } QPixmap NETGENPluginGUI_HypothesisCreator::icon() const { - QString hypIconName = tr( QString("ICON_DLG_NETGEN_PARAMETERS%1").arg(myIs2D?QString("_2D"):QString("")).toLatin1().data() ); + QString hypIconName = tr( myIs2D ? + "ICON_DLG_NETGEN_PARAMETERS_2D" : + "ICON_DLG_NETGEN_PARAMETERS"); return SUIT_Session::session()->resourceMgr()->loadPixmap( "NETGENPlugin", hypIconName ); } QString NETGENPluginGUI_HypothesisCreator::type() const { - return tr( QString( "NETGEN_%1_HYPOTHESIS" ).arg(myIs2D?QString("2D"):QString("3D")).toLatin1().data() ); + return tr( myIs2D ? "NETGEN_2D_HYPOTHESIS" : "NETGEN_3D_HYPOTHESIS"); } QString NETGENPluginGUI_HypothesisCreator::helpPage() const diff --git a/src/GUI/NETGENPluginGUI_HypothesisCreator.h b/src/GUI/NETGENPluginGUI_HypothesisCreator.h index e471ba1..8ca5992 100644 --- a/src/GUI/NETGENPluginGUI_HypothesisCreator.h +++ b/src/GUI/NETGENPluginGUI_HypothesisCreator.h @@ -44,11 +44,11 @@ class QTableWidget; typedef struct { - double myMaxSize, myMinSize, myGrowthRate, myNbSegPerEdge, myNbSegPerRadius, myChordalError; + double myMaxSize, myMinSize, myGrowthRate, myNbSegPerEdge, myNbSegPerRadius, myRidgeAngle, myChordalError; int myFineness; bool mySecondOrder, myAllowQuadrangles, myOptimize, mySurfaceCurvature, myFuseEdges, myChordalErrorEnabled; QString myName, myMeshSizeFile; - QString myMaxSizeVar, myMinSizeVar, myGrowthRateVar, myNbSegPerEdgeVar, myNbSegPerRadiusVar, myChordalErrorVar; + QString myMaxSizeVar, myMinSizeVar, myGrowthRateVar, myNbSegPerEdgeVar, myNbSegPerRadiusVar, myRidgeAngleVar, myChordalErrorVar; } NetgenHypothesisData; /*! @@ -103,6 +103,7 @@ private: SMESHGUI_SpinBox* myGrowthRate; SMESHGUI_SpinBox* myNbSegPerEdge; SMESHGUI_SpinBox* myNbSegPerRadius; + SMESHGUI_SpinBox* myRidgeAngle; QCheckBox* myChordalErrorEnabled; SMESHGUI_SpinBox* myChordalError; QCheckBox* myAllowQuadrangles; diff --git a/src/GUI/NETGENPlugin_msg_en.ts b/src/GUI/NETGENPlugin_msg_en.ts index d73590d..dbde295 100644 --- a/src/GUI/NETGENPlugin_msg_en.ts +++ b/src/GUI/NETGENPlugin_msg_en.ts @@ -95,6 +95,14 @@ NETGEN_CHORDAL_ERROR Chordal Error + + NETGEN_CHORDAL_ERROR + Chordal Error + + + NETGEN_RIDGE_ANGLE + Ridge Angle + NETGEN_SURFACE_CURVATURE Limit Size by Surface Curvature diff --git a/src/NETGENPlugin/CMakeLists.txt b/src/NETGENPlugin/CMakeLists.txt index 5a5b078..cf4120e 100644 --- a/src/NETGENPlugin/CMakeLists.txt +++ b/src/NETGENPlugin/CMakeLists.txt @@ -110,6 +110,7 @@ SET(NETGENEngine_HEADERS NETGENPlugin_SimpleHypothesis_2D_i.hxx NETGENPlugin_SimpleHypothesis_3D_i.hxx NETGENPlugin_Mesher.hxx + NETGENPlugin_Remesher_2D.hxx NETGENPlugin_Defs.hxx ) @@ -136,6 +137,7 @@ SET(NETGENEngine_SOURCES NETGENPlugin_SimpleHypothesis_3D.cxx NETGENPlugin_SimpleHypothesis_2D_i.cxx NETGENPlugin_SimpleHypothesis_3D_i.cxx + NETGENPlugin_Remesher_2D.cxx NETGENPlugin_i.cxx ) diff --git a/src/NETGENPlugin/NETGENPluginBuilder.py b/src/NETGENPlugin/NETGENPluginBuilder.py index 7a2c7fa..858abe2 100644 --- a/src/NETGENPlugin/NETGENPluginBuilder.py +++ b/src/NETGENPlugin/NETGENPluginBuilder.py @@ -106,7 +106,11 @@ class NETGEN_Algorithm(Mesh_Algorithm): def __init__(self, mesh, geom=0): Mesh_Algorithm.__init__(self) 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 @@ -161,6 +165,9 @@ class NETGEN_Algorithm(Mesh_Algorithm): else: hypType = "NETGEN_Parameters_3D" + if self.algo.GetName() == "NETGEN_Remesher_2D": + hypType = "NETGEN_RemesherParameters_2D" + if self.params and self.params.GetName() != hypType: self.mesh.RemoveHypothesis( self.params, self.geom ) self.params = None @@ -229,6 +236,21 @@ class NETGEN_1D2D3D_Algorithm(NETGEN_Algorithm): self.params.SetChordalErrorEnabled( theVal > 0 ) pass + ## Sets @c ChordalError parameter + # @param theVal new value of the @c ChordalError parameter + def SetChordalError(self, theVal): + if self.Parameters(): + self.params.SetChordalError(theVal) + self.params.SetChordalErrorEnabled( theVal > 0 ) + pass + + ## Sets @c RidgeAngle parameter + # @param theVal new value of the @c RidgeAngle parameter + def SetRidgeAngle(self, theVal): + if self.Parameters(): + self.params.SetRidgeAngle(theVal) + pass + ## Sets @c QuadAllowed flag # @param toAllow new value of the @c QuadAllowed parameter (@c True by default) def SetQuadAllowed(self, toAllow=True): diff --git a/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx index ec2fbb5..44f9095 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx @@ -122,10 +122,8 @@ public: static bool GetDefaultFuseEdges(); // Persistence - virtual ostream & SaveTo(ostream & save); - virtual istream & LoadFrom(istream & load); - friend NETGENPLUGIN_EXPORT ostream & operator <<(ostream & save, NETGENPlugin_Hypothesis & hyp); - friend NETGENPLUGIN_EXPORT istream & operator >>(istream & load, NETGENPlugin_Hypothesis & hyp); + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); /*! * \brief Does nothing diff --git a/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.cxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.cxx index 056c592..5db5097 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.cxx @@ -28,7 +28,6 @@ //============================================================================= // #include "NETGENPlugin_Hypothesis_2D.hxx" -#include using namespace std; @@ -51,56 +50,72 @@ NETGENPlugin_Hypothesis_2D::NETGENPlugin_Hypothesis_2D (int hypId, int studyId, * */ //============================================================================= -// 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) +{ + _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 --git a/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.hxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.hxx index b73a3ba..cd0fe5c 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.hxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.hxx @@ -57,4 +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); + + 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 --git a/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D_i.cxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D_i.cxx index e889033..d9cbde4 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D_i.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D_i.cxx @@ -31,11 +31,6 @@ #include "SMESH_Gen.hxx" #include "SMESH_PythonDump.hxx" -#include "Utils_CorbaException.hxx" -#include "utilities.h" - -using namespace std; - //============================================================================= /*! * NETGENPlugin_Hypothesis_2D_i::NETGENPlugin_Hypothesis_2D_i @@ -71,56 +66,97 @@ NETGENPlugin_Hypothesis_2D_i::~NETGENPlugin_Hypothesis_2D_i() //============================================================================= /*! - * NETGENPlugin_Hypothesis_2D_i::SetQuadAllowed + * NETGENPlugin_Hypothesis_2D_i::GetImpl * - * Set QuadAllowed flag + * Get implementation */ //============================================================================= -// void NETGENPlugin_Hypothesis_2D_i::SetQuadAllowed (CORBA::Boolean theValue) -// { -// if ( NETGENPlugin_Hypothesis_i::isToSetParameter( GetQuadAllowed(), -// theValue, -// METH_SetQuadAllowed )) -// { -// this->GetImpl()->SetQuadAllowed(theValue); -// SMESH::TPythonDump() << _this() << ".SetQuadAllowed( " << theValue << " )"; -// } -// } +::NETGENPlugin_Hypothesis_2D* NETGENPlugin_Hypothesis_2D_i::GetImpl() +{ + return (::NETGENPlugin_Hypothesis_2D*)myBaseImpl; +} + +//================================================================================ +/*! + * \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_Hypothesis_2D_i::IsDimSupported( SMESH::Dimension type ) +{ + return type == SMESH::DIM_2D; +} + //============================================================================= /*! - * 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 ) +{ + 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; +} //============================================================================= /*! - * NETGENPlugin_Hypothesis_2D_i::GetImpl + * NETGENPlugin_RemesherHypothesis_2D_i::GetImpl * * Get implementation */ //============================================================================= -::NETGENPlugin_Hypothesis_2D* NETGENPlugin_Hypothesis_2D_i::GetImpl() +::NETGENPlugin_RemesherHypothesis_2D* NETGENPlugin_RemesherHypothesis_2D_i::GetImpl() { - return (::NETGENPlugin_Hypothesis_2D*)myBaseImpl; + return (::NETGENPlugin_RemesherHypothesis_2D*)myBaseImpl; } //================================================================================ /*! - * \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) + * \brief Set ridge angle */ -//================================================================================ -CORBA::Boolean NETGENPlugin_Hypothesis_2D_i::IsDimSupported( SMESH::Dimension type ) +//================================================================================ + +void NETGENPlugin_RemesherHypothesis_2D_i::SetRidgeAngle( CORBA::Double angle ) { - return type == SMESH::DIM_2D; + GetImpl()->SetRidgeAngle( angle ); + + SMESH::TPythonDump() << _this() << ".SetRidgeAngle( " << SMESH::TVar(angle) << " )"; +} + +//================================================================================ +/*! + * \brief Return ridge angle + */ +//================================================================================ + +CORBA::Double NETGENPlugin_RemesherHypothesis_2D_i::GetRidgeAngle() +{ + return GetImpl()->GetRidgeAngle(); } diff --git a/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D_i.hxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D_i.hxx index 55b1c3f..876a361 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D_i.hxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D_i.hxx @@ -70,4 +70,27 @@ class NETGENPLUGIN_EXPORT NETGENPlugin_Hypothesis_2D_i: // }; }; +// 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 --git a/src/NETGENPlugin/NETGENPlugin_Mesher.cxx b/src/NETGENPlugin/NETGENPlugin_Mesher.cxx index 1fa59e4..3ca3d60 100644 --- a/src/NETGENPlugin/NETGENPlugin_Mesher.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Mesher.cxx @@ -818,7 +818,7 @@ void NETGENPlugin_Mesher::SetLocalSizeForChordalError( netgen::OCCGeometry& occg surfProp.SetParameters( uv[0].X(), uv[0].Y() ); if ( !surfProp.IsCurvatureDefined() ) break; - + for ( int n = 0; n < 3; ++n ) // get size at triangle nodes { surfProp.SetParameters( uv[n].X(), uv[n].Y() ); @@ -1111,8 +1111,7 @@ bool NETGENPlugin_Mesher::FillNgMesh(netgen::OCCGeometry& occgeom, // get all nodes from connected const bool isQuad = smDS->IsQuadratic(); - //StdMeshers_FaceSide fSide( face, edges, _mesh, isForwad, isQuad, &helper ); -- master - StdMeshers_FaceSide fSide( face, edges, _mesh, isForwad, isQuad ); // -- V8_2_BR + StdMeshers_FaceSide fSide( face, edges, _mesh, isForwad, isQuad ); const vector& points = fSide.GetUVPtStruct(); if ( points.empty() ) return false; // invalid node params? @@ -3069,8 +3068,7 @@ bool NETGENPlugin_Mesher::Compute() helper.SetSubShape( F ); TSideVector wires = StdMeshers_FaceSide::GetFaceWires( F, *_mesh, /*skipMediumNodes=*/true, - error, viscousMesh ); // -- V8_2_BR - // error, &helper, viscousMesh ); -- master + error, viscousMesh ); error = AddSegmentsToMesh( *_ngMesh, occgeo, wires, helper, nodeVec ); if ( !error ) error = SMESH_ComputeError::New(); diff --git a/src/NETGENPlugin/NETGENPlugin_Mesher.hxx b/src/NETGENPlugin/NETGENPlugin_Mesher.hxx index 41d9aa5..608de2a 100644 --- a/src/NETGENPlugin/NETGENPlugin_Mesher.hxx +++ b/src/NETGENPlugin/NETGENPlugin_Mesher.hxx @@ -220,7 +220,7 @@ class NETGENPLUGIN_EXPORT NETGENPlugin_Mesher // a pointer to NETGENPlugin_Mesher* field of the holder, that will be // nullified at destruction of this - NETGENPlugin_Mesher ** _ptrToMe; + NETGENPlugin_Mesher ** _ptrToMe; }; //============================================================================= diff --git a/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_i.cxx b/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_i.cxx index 96d1f07..be39bd8 100644 --- a/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_i.cxx +++ b/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_i.cxx @@ -27,13 +27,9 @@ // $Header$ // #include "NETGENPlugin_NETGEN_2D_i.hxx" +#include "NETGENPlugin_Remesher_2D.hxx" #include "SMESH_Gen.hxx" -#include "Utils_CorbaException.hxx" -#include "utilities.h" - -using namespace std; - //============================================================================= /*! * NETGENPlugin_NETGEN_2D_i::NETGENPlugin_NETGEN_2D_i @@ -79,3 +75,38 @@ NETGENPlugin_NETGEN_2D_i::~NETGENPlugin_NETGEN_2D_i() { 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 --git a/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_i.hxx b/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_i.hxx index 695ff80..ea9f210 100644 --- a/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_i.hxx +++ b/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_i.hxx @@ -38,7 +38,7 @@ #include "NETGENPlugin_NETGEN_2D.hxx" // ====================================================== -// NETGEN 3d algorithm +// NETGEN 1D2D algorithm // ====================================================== class NETGENPLUGIN_EXPORT NETGENPlugin_NETGEN_2D_i: public virtual POA_NETGENPlugin::NETGENPlugin_NETGEN_2D, @@ -56,4 +56,23 @@ 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 --git a/src/NETGENPlugin/NETGENPlugin_Remesher_2D.cxx b/src/NETGENPlugin/NETGENPlugin_Remesher_2D.cxx new file mode 100644 index 0000000..49b5877 --- /dev/null +++ b/src/NETGENPlugin/NETGENPlugin_Remesher_2D.cxx @@ -0,0 +1,692 @@ +// 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(); } + + private: + SMESHDS_Mesh* myMeshDS; + std::vector< std::vector< gp_XYZ > > myHole; // initial border nodes + std::vector< gp_XYZ > myInHolePos; // position inside each hole + }; + + //================================================================================ + /*! + * \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 + SMESH_ComputeErrorPtr error = + SMESH_ComputeError::New( COMPERR_BAD_INPUT_MESH, + "Non-manifold mesh. Only manifold mesh can be re-meshed"); + 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("Non-manifold mesh. Only manifold mesh can be re-meshed"); + } + + // 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.; + // 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; + + 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) +{ + _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 + Bnd_B3d box; + 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() ); + box.Add( n1 ); + box.Add( n2 ); + box.Add( n3 ); + if ( f->NbNodes() > 3 ) + { + n2.Set( f->GetNode( 3 )); + Ng_STL_AddTriangle( ngStlGeo, + n1.ChangeData(), + n3.ChangeData(), + n2.ChangeData()); + box.Add( n2 ); + } + } + // 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 = Sqrt( box.SquareExtent() ); + netgen::mparam.maxh = diagSize / GetGen()->GetBoundaryBoxSegmentation(); + netgen::mparam.minh = netgen::mparam.maxh; + } + + double h = netgen::mparam.maxh; + gp_XYZ pMin = box.CornerMin() - gp_XYZ(h, h, h); + gp_XYZ pMax = box.CornerMax() + gp_XYZ(h, h, h); + ngMesh->SetGlobalH( h ); + ngMesh->SetMinimalH( netgen::mparam.minh ); + ngMesh->SetLocalH( netgen::Point3d(pMin.X(), pMin.Y(), pMin.Z()), + netgen::Point3d(pMax.X(), pMax.Y(), pMax.Z()), + 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 + 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 --git a/src/NETGENPlugin/NETGENPlugin_Remesher_2D.hxx b/src/NETGENPlugin/NETGENPlugin_Remesher_2D.hxx new file mode 100644 index 0000000..be9a161 --- /dev/null +++ b/src/NETGENPlugin/NETGENPlugin_Remesher_2D.hxx @@ -0,0 +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); + + 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 diff --git a/src/NETGENPlugin/NETGENPlugin_i.cxx b/src/NETGENPlugin/NETGENPlugin_i.cxx index 7cf2c10..a74e633 100644 --- a/src/NETGENPlugin/NETGENPlugin_i.cxx +++ b/src/NETGENPlugin/NETGENPlugin_i.cxx @@ -69,6 +69,8 @@ extern "C" aCreator = new NETGENPlugin_Creator_i; else if (strcmp(aHypName, "NETGEN_2D3D") == 0) aCreator = new NETGENPlugin_Creator_i; + else if (strcmp(aHypName, "NETGEN_Remesher_2D") == 0) + aCreator = new NETGENPlugin_Creator_i; // Hypotheses else if (strcmp(aHypName, "NETGEN_Parameters") == 0) aCreator = new NETGENPlugin_Creator_i; @@ -82,6 +84,8 @@ extern "C" aCreator = new NETGENPlugin_Creator_i; else if (strcmp(aHypName, "NETGEN_SimpleParameters_3D") == 0) aCreator = new NETGENPlugin_Creator_i; + else if (strcmp(aHypName, "NETGEN_RemesherParameters_2D") == 0) + aCreator = new NETGENPlugin_Creator_i; else ; return aCreator; -- 2.39.2