From: eap Date: Tue, 17 Oct 2017 14:38:39 +0000 (+0300) Subject: GPUSPHGUI: create a 2D remesher algo and add Chordal Error parameter X-Git-Tag: V9_0_0~1^2~3 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=a7d2d2391062ed5776d1a2368cc96cedd6de8e46;p=plugins%2Fnetgenplugin.git GPUSPHGUI: create a 2D remesher algo and add Chordal Error parameter --- diff --git a/doc/salome/gui/NETGENPLUGIN/images/netgen2d3d.png b/doc/salome/gui/NETGENPLUGIN/images/netgen2d3d.png index dbf9795..17f9d55 100644 Binary files a/doc/salome/gui/NETGENPLUGIN/images/netgen2d3d.png and b/doc/salome/gui/NETGENPLUGIN/images/netgen2d3d.png differ diff --git a/doc/salome/gui/NETGENPLUGIN/images/netgen2d3d_only.png b/doc/salome/gui/NETGENPLUGIN/images/netgen2d3d_only.png index 4b57432..f0abed3 100644 Binary files a/doc/salome/gui/NETGENPLUGIN/images/netgen2d3d_only.png and b/doc/salome/gui/NETGENPLUGIN/images/netgen2d3d_only.png differ 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..67eef4f Binary files /dev/null and b/doc/salome/gui/NETGENPLUGIN/images/netgen2d_remesher.png differ 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 4ef8e06..9e34081 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). @@ -31,13 +35,19 @@ parameters below. You can select \a Custom to define them manually. - Growth rate - allows to define how much the linear dimensions of two adjacent cells can differ (e.g. 0.3 means 30%). - Nb. Segs per Edge - allows to define the minimum number of -mesh segments in which edges will be split. This parameter is used -only if Limit Size by Surface Curvature is checked. +mesh segments in which edges will be split. Size of elements computed using +this value is trimmed between Min Size and Max Size +bounds. This parameter is used only if Limit Size by Surface + Curvature is checked. - Nb Segs per Radius - allows to define the size of mesh segments and mesh faces in which curved edges and surfaces will -be split. This value divided by a radius of curvature gives an element -size at a given point. This parameter is used only if Limit Size by - Surface Curvature is checked. +be split. A radius of local curvature divided by this value gives an element +size at a given point. Element size computed this way is then trimmed +between Min Size and Max Size bounds. This parameter is +used only if Limit Size by Surface Curvature is checked. +- Chordal Error - allows to define the maximum distance between +the generated 2D element and the surface. Size of elements computed using +this criterion is trimmed between Min Size and Max Size bounds. - Limit Size by Surface Curvature - if this box is checked in, then size of mesh segments and mesh faces on curved edges and surfaces is defined using value of Nb Segs per Radius parameter, and @@ -55,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 @@ -70,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 @@ -87,6 +102,7 @@ section.
"25 25 0 25 25 200 0.3" means that along the line between points (25, 25, 0) and (25, 25, 200) size of elements should be 0.3. + \image html netgen2d3d_simple.png NETGEN 2D simple parameters and NETGEN 3D simple @@ -124,6 +140,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 5a0b252..a69c4f9 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,6 +100,11 @@ module NETGENPlugin void SetNbSegPerEdge(in double value); double GetNbSegPerEdge(); + void SetChordalErrorEnabled(in boolean value); + boolean GetChordalErrorEnabled(); + void SetChordalError(in double value); + double GetChordalError(); + void SetNbSegPerRadius(in double value); double GetNbSegPerRadius(); @@ -136,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 d7d7651..3e173c1 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 2db7d1e..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 ); @@ -177,7 +183,7 @@ QFrame* NETGENPluginGUI_HypothesisCreator::buildFrame() myFineness = new QComboBox( GroupC1 ); QStringList types; types << tr( "NETGEN_VERYCOARSE" ) << tr( "NETGEN_COARSE" ) << tr( "NETGEN_MODERATE" ) << - tr( "NETGEN_FINE" ) << tr( "NETGEN_VERYFINE" ) << tr( "NETGEN_CUSTOM" ); + tr( "NETGEN_FINE" ) << tr( "NETGEN_VERYFINE" ) << tr( "NETGEN_CUSTOM" ); myFineness->addItems( types ); aGroupLayout->addWidget( myFineness, row, 1 ); connect( myFineness, SIGNAL( activated( int ) ), this, SLOT( onFinenessChanged() ) ); @@ -208,8 +214,31 @@ QFrame* NETGENPluginGUI_HypothesisCreator::buildFrame() row++; } + myChordalErrorEnabled = 0; + myChordalError = 0; + if (( myIs2D && !isRemesher ) || !myIsONLY ) + { + myChordalErrorEnabled = new QCheckBox( tr( "NETGEN_CHORDAL_ERROR" ), GroupC1 ); + aGroupLayout->addWidget( myChordalErrorEnabled, row, 0 ); + myChordalError = new SMESHGUI_SpinBox( GroupC1 ); + myChordalError->RangeStepAndValidator( COORD_MIN, COORD_MAX, .1, "length_precision" ); + aGroupLayout->addWidget( myChordalError, row, 1 ); + connect( myChordalErrorEnabled, SIGNAL( stateChanged(int)), SLOT( onChordalErrorEnabled())); + 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 ); @@ -225,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 ); @@ -337,6 +370,22 @@ void NETGENPluginGUI_HypothesisCreator::retrieveParams() const else myNbSegPerRadius->setText( data.myNbSegPerRadiusVar ); } + if ( myChordalError ) + { + myChordalErrorEnabled->setChecked( data.myChordalErrorEnabled && data.myChordalError > 0 ); + if(data.myChordalErrorVar.isEmpty()) + myChordalError->setValue( data.myChordalError > 0 ? data.myChordalError : 0.1 ); + else + 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 ); @@ -381,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 @@ -408,35 +457,45 @@ bool NETGENPluginGUI_HypothesisCreator::readParamsFromHypo( NetgenHypothesisData NETGENPlugin::NETGENPlugin_Hypothesis_var h = NETGENPlugin::NETGENPlugin_Hypothesis::_narrow( initParamsHypothesis() ); - //HypothesisData* data = SMESH::GetHypothesisData( hypType() ); h_data.myName = isCreation() ? hypName() : ""; - h_data.myMaxSize = h->GetMaxSize(); - h_data.myMaxSizeVar = getVariableName("SetMaxSize"); + h_data.myMaxSize = h->GetMaxSize(); + h_data.myMaxSizeVar = getVariableName("SetMaxSize"); h_data.mySecondOrder = h->GetSecondOrder(); - h_data.myOptimize = h->GetOptimize(); - - h_data.myFineness = (int) h->GetFineness(); - h_data.myGrowthRate = h->GetGrowthRate(); - h_data.myGrowthRateVar = getVariableName("SetGrowthRate"); - h_data.myNbSegPerEdge = h->GetNbSegPerEdge(); - h_data.myNbSegPerEdgeVar = getVariableName("SetNbSegPerEdge"); - h_data.myNbSegPerRadius = h->GetNbSegPerRadius(); - h_data.myNbSegPerRadiusVar = getVariableName("SetNbSegPerRadius"); - h_data.myMinSize = h->GetMinSize(); - h_data.myMinSizeVar = getVariableName("SetMinSize"); - h_data.mySurfaceCurvature = h->GetUseSurfaceCurvature(); - h_data.myFuseEdges = h->GetFuseEdges(); - h_data.myMeshSizeFile = h->GetMeshSizeFile(); + h_data.myOptimize = h->GetOptimize(); + + h_data.myFineness = (int) h->GetFineness(); + h_data.myGrowthRate = h->GetGrowthRate(); + h_data.myGrowthRateVar = getVariableName("SetGrowthRate"); + h_data.myNbSegPerEdge = h->GetNbSegPerEdge(); + h_data.myNbSegPerEdgeVar = getVariableName("SetNbSegPerEdge"); + h_data.myNbSegPerRadius = h->GetNbSegPerRadius(); + h_data.myNbSegPerRadiusVar = getVariableName("SetNbSegPerRadius"); + h_data.myChordalError = h->GetChordalError(); + h_data.myChordalErrorVar = getVariableName("SetChordalError"); + h_data.myChordalErrorEnabled = h->GetChordalErrorEnabled(); + h_data.myMinSize = h->GetMinSize(); + h_data.myMinSizeVar = getVariableName("SetMinSize"); + h_data.mySurfaceCurvature = h->GetUseSurfaceCurvature(); + h_data.myFuseEdges = h->GetFuseEdges(); + h_data.myMeshSizeFile = h->GetMeshSizeFile(); //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(); @@ -472,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 ); @@ -481,31 +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.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__") { @@ -513,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()); } } } @@ -551,8 +631,18 @@ bool NETGENPluginGUI_HypothesisCreator::readParamsFromWidgets( NetgenHypothesisD h_data.myNbSegPerEdgeVar = myNbSegPerEdge->text(); if ( myNbSegPerRadius ) h_data.myNbSegPerRadiusVar = myNbSegPerRadius->text(); + if ( myChordalError ) + { + h_data.myChordalErrorVar = myChordalError->text(); + 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(); @@ -577,6 +667,11 @@ bool NETGENPluginGUI_HypothesisCreator::readParamsFromWidgets( NetgenHypothesisD return true; } +void NETGENPluginGUI_HypothesisCreator::onChordalErrorEnabled() +{ + myChordalError->setEnabled( myChordalErrorEnabled->isChecked() ); +} + void NETGENPluginGUI_HypothesisCreator::onSurfaceCurvatureChanged() { bool isSurfaceCurvature = (mySurfaceCurvature ? mySurfaceCurvature->isChecked() : true); @@ -587,12 +682,17 @@ void NETGENPluginGUI_HypothesisCreator::onSurfaceCurvatureChanged() myNbSegPerEdge->setEnabled(isCustom && isSurfaceCurvature); if ( myNbSegPerRadius ) myNbSegPerRadius->setEnabled(isCustom && isSurfaceCurvature); + // if ( myChordalError ) + // { + // myChordalError->setEnabled( isSurfaceCurvature ); + // myChordalErrorEnabled->setEnabled( isSurfaceCurvature ); + // } } void NETGENPluginGUI_HypothesisCreator::onFinenessChanged() { bool isCustom = (myFineness->currentIndex() == UserDefined); - + myGrowthRate->setEnabled(isCustom); if ( myNbSegPerEdge ) myNbSegPerEdge->setEnabled(isCustom); @@ -600,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() @@ -670,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() @@ -735,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); } @@ -777,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 64a1616..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; - int myFineness; - bool mySecondOrder, myAllowQuadrangles, myOptimize, mySurfaceCurvature, myFuseEdges; - QString myName, myMeshSizeFile; - QString myMaxSizeVar, myMinSizeVar, myGrowthRateVar, myNbSegPerEdgeVar, myNbSegPerRadiusVar; + 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, myRidgeAngleVar, myChordalErrorVar; } NetgenHypothesisData; /*! @@ -76,6 +76,7 @@ protected: protected slots: virtual void onFinenessChanged(); + virtual void onChordalErrorEnabled(); virtual void onSurfaceCurvatureChanged(); virtual void onAddLocalSizeOnVertex(); virtual void onAddLocalSizeOnEdge(); @@ -102,12 +103,15 @@ private: SMESHGUI_SpinBox* myGrowthRate; SMESHGUI_SpinBox* myNbSegPerEdge; SMESHGUI_SpinBox* myNbSegPerRadius; + SMESHGUI_SpinBox* myRidgeAngle; + QCheckBox* myChordalErrorEnabled; + SMESHGUI_SpinBox* myChordalError; QCheckBox* myAllowQuadrangles; QCheckBox* mySurfaceCurvature; QCheckBox* myFuseEdges; - bool myIs2D; - bool myIsONLY; + bool myIs2D; // 2D or 3D + bool myIsONLY; // one dim or several QLineEdit* myMeshSizeFile; QTableWidget* myLocalSizeTable; diff --git a/src/GUI/NETGENPlugin_msg_en.ts b/src/GUI/NETGENPlugin_msg_en.ts index 139fb85..9f1050b 100644 --- a/src/GUI/NETGENPlugin_msg_en.ts +++ b/src/GUI/NETGENPlugin_msg_en.ts @@ -91,6 +91,14 @@ NETGEN_SEG_PER_RADIUS Nb. Segs per Radius + + 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 d5f9460..7334ae3 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 @@ -221,6 +228,21 @@ class NETGEN_1D2D3D_Algorithm(NETGEN_Algorithm): if self.Parameters(): self.params.SetNbSegPerRadius(theVal) 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.cxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis.cxx index fe4c2ee..9bd9ec8 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis.cxx @@ -43,18 +43,20 @@ using namespace std; NETGENPlugin_Hypothesis::NETGENPlugin_Hypothesis (int hypId, int studyId, SMESH_Gen * gen) : SMESH_Hypothesis(hypId, studyId, 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; @@ -208,6 +210,34 @@ void NETGENPlugin_Hypothesis::SetNbSegPerRadius(double theVal) } } +//============================================================================= +/*! + * + */ +//============================================================================= +void NETGENPlugin_Hypothesis::SetChordalErrorEnabled(bool theVal) +{ + if (theVal != _chordalErrorEnabled) + { + _chordalErrorEnabled = theVal; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * + */ +//============================================================================= +void NETGENPlugin_Hypothesis::SetChordalError(double theVal) +{ + if (theVal != _chordalError) + { + _chordalError = theVal; + NotifySubMeshesHypothesisModification(); + } +} + //============================================================================= /*! * @@ -351,8 +381,8 @@ ostream & NETGENPlugin_Hypothesis::SaveTo(ostream & save) if (it_sm != _localSize.end()) { save << " " << "__LOCALSIZE_BEGIN__"; for ( ; it_sm != _localSize.end(); ++it_sm ) { - save << " " << it_sm->first - << " " << it_sm->second << "%#"; // "%#" is a mark of value end + save << " " << it_sm->first + << " " << it_sm->second << "%#"; // "%#" is a mark of value end } save << " " << "__LOCALSIZE_END__"; } @@ -363,6 +393,8 @@ ostream & NETGENPlugin_Hypothesis::SaveTo(ostream & save) save << " " << _meshSizeFile.size() << " " << _meshSizeFile; + save << " " << ( _chordalErrorEnabled ? _chordalError : 0. ); + return save; } @@ -476,12 +508,19 @@ istream & NETGENPlugin_Hypothesis::LoadFrom(istream & load) load.get( &_meshSizeFile[0], is+1 ); } + isOK = static_cast(load >> val); + if (isOK) + _chordalError = val; + else + load.clear(ios::badbit | load.rdstate()); + _chordalErrorEnabled = ( _chordalError > 0 ); + return load; } //============================================================================= /*! - * + * */ //============================================================================= ostream & operator <<(ostream & save, NETGENPlugin_Hypothesis & hyp) @@ -491,7 +530,7 @@ ostream & operator <<(ostream & save, NETGENPlugin_Hypothesis & hyp) //============================================================================= /*! - * + * */ //============================================================================= istream & operator >>(istream & load, NETGENPlugin_Hypothesis & hyp) @@ -584,6 +623,15 @@ double NETGENPlugin_Hypothesis::GetDefaultNbSegPerRadius() { return 2; } +//============================================================================= +/*! + * + */ +//============================================================================= +double NETGENPlugin_Hypothesis::GetDefaultChordalError() +{ + return -1; // disabled by default +} //============================================================================= /*! diff --git a/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx index 7d6da32..44f9095 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx @@ -83,6 +83,11 @@ public: void SetNbSegPerRadius(double theVal); double GetNbSegPerRadius() const { return _nbSegPerRadius; } + void SetChordalErrorEnabled(bool value); + double GetChordalErrorEnabled() const { return _chordalErrorEnabled; } + void SetChordalError(double value); + double GetChordalError() const { return _chordalError; } + typedef std::map TLocalSize; static TLocalSize GetDefaultLocalSize() { return TLocalSize(); } void SetLocalSizeOnEntry(const std::string& entry, double localSize); @@ -109,6 +114,7 @@ public: static double GetDefaultGrowthRate(); static double GetDefaultNbSegPerEdge(); static double GetDefaultNbSegPerRadius(); + static double GetDefaultChordalError(); static bool GetDefaultSecondOrder(); static bool GetDefaultOptimize(); static bool GetDefaultQuadAllowed(); @@ -116,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 @@ -141,6 +145,8 @@ private: double _nbSegPerEdge; double _nbSegPerRadius; Fineness _fineness; + bool _chordalErrorEnabled; + double _chordalError; bool _secondOrder; bool _optimize; TLocalSize _localSize; 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_Hypothesis_i.cxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.cxx index d60d666..11461d6 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.cxx @@ -307,6 +307,36 @@ CORBA::Double NETGENPlugin_Hypothesis_i::GetNbSegPerRadius() //============================================================================= +void NETGENPlugin_Hypothesis_i::SetChordalErrorEnabled(CORBA::Boolean theValue) +{ + if ( isToSetParameter( GetChordalErrorEnabled(), theValue, METH_SetChordalErrorEnabled )) + { + this->GetImpl()->SetChordalErrorEnabled(theValue); + SMESH::TPythonDump() << _this() << ".SetChordalErrorEnabled( " << theValue << " )"; + } +} + +CORBA::Boolean NETGENPlugin_Hypothesis_i::GetChordalErrorEnabled() +{ + return GetImpl()->GetChordalErrorEnabled(); +} + +void NETGENPlugin_Hypothesis_i::SetChordalError(CORBA::Double theValue) +{ + if ( isToSetParameter( GetChordalError(), theValue, METH_SetChordalError )) + { + this->GetImpl()->SetChordalError(theValue); + SMESH::TPythonDump() << _this() << ".SetChordalError( " << SMESH::TVar(theValue) << " )"; + } +} + +CORBA::Double NETGENPlugin_Hypothesis_i::GetChordalError() +{ + return GetImpl()->GetChordalError(); +} + +//============================================================================= + void NETGENPlugin_Hypothesis_i::SetLocalSizeOnShape(GEOM::GEOM_Object_ptr GeomObj, CORBA::Double localSize) throw (SALOME::SALOME_Exception) diff --git a/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.hxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.hxx index 12ffa7b..e9b908d 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.hxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.hxx @@ -79,6 +79,11 @@ class NETGENPLUGIN_EXPORT NETGENPlugin_Hypothesis_i: void SetNbSegPerRadius(CORBA::Double theVal); CORBA::Double GetNbSegPerRadius(); + void SetChordalErrorEnabled(CORBA::Boolean value); + CORBA::Boolean GetChordalErrorEnabled(); + void SetChordalError(CORBA::Double value); + CORBA::Double GetChordalError(); + void SetLocalSizeOnShape(GEOM::GEOM_Object_ptr GeomObj, CORBA::Double localSize) throw (SALOME::SALOME_Exception); void SetLocalSizeOnEntry(const char* entry, CORBA::Double localSize); @@ -109,19 +114,21 @@ class NETGENPLUGIN_EXPORT NETGENPlugin_Hypothesis_i: // to remember whether a parameter is already set (issue 0021364) enum SettingMethod { - METH_SetMaxSize = 1, - METH_SetMinSize = 2, - METH_SetSecondOrder = 4, - METH_SetOptimize = 8, - METH_SetFineness = 16, - METH_SetGrowthRate = 32, - METH_SetNbSegPerEdge = 64, - METH_SetNbSegPerRadius = 128, - METH_SetLocalSizeOnEntry = 256, - METH_SetQuadAllowed = METH_SetLocalSizeOnEntry * 2, - METH_SetSurfaceCurvature = METH_SetQuadAllowed * 2, - METH_SetFuseEdges = METH_SetSurfaceCurvature * 2, - METH_LAST = METH_SetFuseEdges + METH_SetMaxSize = 1, + METH_SetMinSize = 2, + METH_SetSecondOrder = 4, + METH_SetOptimize = 8, + METH_SetFineness = 16, + METH_SetGrowthRate = 32, + METH_SetNbSegPerEdge = 64, + METH_SetNbSegPerRadius = 128, + METH_SetLocalSizeOnEntry = 256, + METH_SetQuadAllowed = METH_SetLocalSizeOnEntry * 2, + METH_SetSurfaceCurvature = METH_SetQuadAllowed * 2, + METH_SetFuseEdges = METH_SetSurfaceCurvature * 2, + METH_SetChordalErrorEnabled = METH_SetFuseEdges * 2, + METH_SetChordalError = METH_SetChordalErrorEnabled * 2, + METH_LAST = METH_SetFuseEdges }; int mySetMethodFlags; diff --git a/src/NETGENPlugin/NETGENPlugin_Mesher.cxx b/src/NETGENPlugin/NETGENPlugin_Mesher.cxx index dc3afe7..c343224 100644 --- a/src/NETGENPlugin/NETGENPlugin_Mesher.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Mesher.cxx @@ -52,21 +52,29 @@ #include +#include #include +#include +#include +#include #include #include +#include #include +#include #include #include #include #include #include +#include #include #include #include #include #include #include +#include // Netgen include files #ifndef OCCGEOMETRY @@ -151,6 +159,7 @@ NETGENPlugin_Mesher::NETGENPlugin_Mesher (SMESH_Mesh* mesh, _optimize(true), _fineness(NETGENPlugin_Hypothesis::GetDefaultFineness()), _isViscousLayers2D(false), + _chordalError(-1), // means disabled _ngMesh(NULL), _occgeom(NULL), _curShapeIndex(-1), @@ -293,32 +302,36 @@ void NETGENPlugin_Mesher::SetParameters(const NETGENPlugin_Hypothesis* hyp) _fineness = hyp->GetFineness(); mparams.uselocalh = hyp->GetSurfaceCurvature(); netgen::merge_solids = hyp->GetFuseEdges(); + _chordalError = hyp->GetChordalErrorEnabled() ? hyp->GetChordalError() : -1.; _simpleHyp = NULL; // mesh size file mparams.meshsizefilename= hyp->GetMeshSizeFile().empty() ? 0 : hyp->GetMeshSizeFile().c_str(); - 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() ) + const NETGENPlugin_Hypothesis::TLocalSize& localSizes = hyp->GetLocalSizesAndEntries(); + if ( !localSizes.empty() ) { - const NETGENPlugin_Hypothesis::TLocalSize localSizes = hyp->GetLocalSizesAndEntries(); - NETGENPlugin_Hypothesis::TLocalSize::const_iterator it = localSizes.begin(); - for ( ; it != localSizes.end() ; it++) + 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() ) { - 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(); + 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); } - TopoDS_Shape S = smeshGen_i->GeomObjectToShape( aGeomObj.in() ); - ::SetLocalSize(S, val); } } } @@ -597,7 +610,8 @@ namespace void setLocalSize(const TopoDS_Edge& edge, double size, - netgen::Mesh& mesh) + netgen::Mesh& mesh, + const bool overrideMinH = true) { if ( size <= std::numeric_limits::min() ) return; @@ -608,7 +622,7 @@ namespace TopoDS_Iterator vIt( edge ); if ( !vIt.More() ) return; gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( vIt.Value() )); - NETGENPlugin_Mesher::RestrictLocalSize( mesh, p.XYZ(), size ); + NETGENPlugin_Mesher::RestrictLocalSize( mesh, p.XYZ(), size, overrideMinH ); } else { @@ -618,15 +632,29 @@ namespace { Standard_Real u = u1 + delta*i; gp_Pnt p = curve->Value(u); - NETGENPlugin_Mesher::RestrictLocalSize( mesh, p.XYZ(), size ); + NETGENPlugin_Mesher::RestrictLocalSize( mesh, p.XYZ(), size, overrideMinH ); netgen::Point3d pi(p.X(), p.Y(), p.Z()); double resultSize = mesh.GetH(pi); if ( resultSize - size > 0.1*size ) // netgen does restriction iff oldH/newH > 1.2 (localh.cpp:136) - NETGENPlugin_Mesher::RestrictLocalSize( mesh, p.XYZ(), resultSize/1.201 ); + NETGENPlugin_Mesher::RestrictLocalSize( mesh, p.XYZ(), resultSize/1.201, overrideMinH ); } } } + + //================================================================================ + /*! + * \brief Return triangle size for a given chordalError and radius of curvature + */ + //================================================================================ + + double elemSizeForChordalError( double chordalError, double radius ) + { + if ( 2 * radius < chordalError ) + return 1.5 * radius; + return Sqrt( 3 ) * Sqrt( chordalError * ( 2 * radius - chordalError )); + } + } // namespace //================================================================================ @@ -636,16 +664,19 @@ namespace //================================================================================ void NETGENPlugin_Mesher::SetLocalSize( netgen::OCCGeometry& occgeo, - netgen::Mesh& ngMesh ) + netgen::Mesh& ngMesh) { - for(std::map::const_iterator it=EdgeId2LocalSize.begin(); it!=EdgeId2LocalSize.end(); it++) + // edges + std::map::const_iterator it; + for( it=EdgeId2LocalSize.begin(); it!=EdgeId2LocalSize.end(); it++) { int key = (*it).first; double hi = (*it).second; const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key); setLocalSize( TopoDS::Edge(shape), hi, ngMesh ); } - for(std::map::const_iterator it=VertexId2LocalSize.begin(); it!=VertexId2LocalSize.end(); it++) + // vertices + for(it=VertexId2LocalSize.begin(); it!=VertexId2LocalSize.end(); it++) { int key = (*it).first; double hi = (*it).second; @@ -653,7 +684,8 @@ void NETGENPlugin_Mesher::SetLocalSize( netgen::OCCGeometry& occgeo, gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex(shape) ); NETGENPlugin_Mesher::RestrictLocalSize( ngMesh, p.XYZ(), hi ); } - for(map::const_iterator it=FaceId2LocalSize.begin(); it!=FaceId2LocalSize.end(); it++) + // faces + for(it=FaceId2LocalSize.begin(); it!=FaceId2LocalSize.end(); it++) { int key = (*it).first; double val = (*it).second; @@ -671,7 +703,8 @@ void NETGENPlugin_Mesher::SetLocalSize( netgen::OCCGeometry& occgeo, ShapesWithControlPoints.insert( key ); } } - for(map::const_iterator it=SolidId2LocalSize.begin(); it!=SolidId2LocalSize.end(); it++) + //solids + for(it=SolidId2LocalSize.begin(); it!=SolidId2LocalSize.end(); it++) { int key = (*it).first; double val = (*it).second; @@ -688,6 +721,146 @@ void NETGENPlugin_Mesher::SetLocalSize( netgen::OCCGeometry& occgeo, for ( size_t i = 0; i < ControlPoints.size(); ++i ) NETGENPlugin_Mesher::RestrictLocalSize( ngMesh, ControlPoints[i].XYZ(), ControlPoints[i].Size() ); } + return; +} + +//================================================================================ +/*! + * \brief Restrict local size to achieve a required _chordalError + */ +//================================================================================ + +void NETGENPlugin_Mesher::SetLocalSizeForChordalError( netgen::OCCGeometry& occgeo, + netgen::Mesh& ngMesh) +{ + if ( _chordalError <= 0. ) + return; + + TopLoc_Location loc; + BRepLProp_SLProps surfProp( 2, 1e-6 ); + const double sizeCoef = 0.95; + + // find non-planar FACEs with non-constant curvature + std::vector fInd; + for ( int i = 1; i <= occgeo.fmap.Extent(); ++i ) + { + const TopoDS_Face& face = TopoDS::Face( occgeo.fmap( i )); + BRepAdaptor_Surface surfAd( face, false ); + switch ( surfAd.GetType() ) + { + case GeomAbs_Plane: + continue; + case GeomAbs_Cylinder: + case GeomAbs_Sphere: + case GeomAbs_Torus: // constant curvature + { + surfProp.SetSurface( surfAd ); + surfProp.SetParameters( 0, 0 ); + double maxCurv = Max( Abs( surfProp.MaxCurvature()), Abs( surfProp.MinCurvature() )); + double size = elemSizeForChordalError( _chordalError, 1 / maxCurv ); + occgeo.SetFaceMaxH( i, size * sizeCoef ); + // limit size one edges + TopTools_MapOfShape edgeMap; + for ( TopExp_Explorer eExp( face, TopAbs_EDGE ); eExp.More(); eExp.Next() ) + if ( edgeMap.Add( eExp.Current() )) + setLocalSize( TopoDS::Edge( eExp.Current() ), size, ngMesh, /*overrideMinH=*/false ); + break; + } + default: + Handle(Geom_Surface) surf = BRep_Tool::Surface( face, loc ); + if ( GeomLib_IsPlanarSurface( surf ).IsPlanar() ) + continue; + fInd.push_back( i ); + } + } + // set local size + if ( !fInd.empty() ) + { + BRep_Builder b; + TopoDS_Compound allFacesComp; + b.MakeCompound( allFacesComp ); + for ( size_t i = 0; i < fInd.size(); ++i ) + b.Add( allFacesComp, occgeo.fmap( fInd[i] )); + + // copy the shape to avoid spoiling its triangulation + TopoDS_Shape allFacesCompCopy = BRepBuilderAPI_Copy( allFacesComp ); + + // create triangulation with desired chordal error + BRepMesh_IncrementalMesh( allFacesCompCopy, + _chordalError, + /*isRelative = */Standard_False, + /*theAngDeflection = */ 0.5, + /*isInParallel = */Standard_True); + + // loop on FACEs + for ( TopExp_Explorer fExp( allFacesCompCopy, TopAbs_FACE ); fExp.More(); fExp.Next() ) + { + const TopoDS_Face& face = TopoDS::Face( fExp.Current() ); + Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation ( face, loc ); + if ( triangulation.IsNull() ) continue; + + BRepAdaptor_Surface surf( face, false ); + surfProp.SetSurface( surf ); + + gp_XY uv[3]; + gp_XYZ p[3]; + double size[3]; + for ( int i = 1; i <= triangulation->NbTriangles(); ++i ) + { + Standard_Integer n1,n2,n3; + triangulation->Triangles()(i).Get( n1,n2,n3 ); + p [0] = triangulation->Nodes()(n1).Transformed(loc).XYZ(); + p [1] = triangulation->Nodes()(n2).Transformed(loc).XYZ(); + p [2] = triangulation->Nodes()(n3).Transformed(loc).XYZ(); + uv[0] = triangulation->UVNodes()(n1).XY(); + uv[1] = triangulation->UVNodes()(n2).XY(); + uv[2] = triangulation->UVNodes()(n3).XY(); + 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() ); + double maxCurv = Max( Abs( surfProp.MaxCurvature()), Abs( surfProp.MinCurvature() )); + size[n] = elemSizeForChordalError( _chordalError, 1 / maxCurv ); + } + for ( int n1 = 0; n1 < 3; ++n1 ) // limit size along each triangle edge + { + int n2 = ( n1 + 1 ) % 3; + double minSize = size[n1], maxSize = size[n2]; + if ( size[n1] > size[n2] ) + minSize = size[n2], maxSize = size[n1]; + + if ( maxSize / minSize < 1.2 ) // netgen ignores size difference < 1.2 + { + ngMesh.RestrictLocalHLine ( netgen::Point3d( p[n1].X(), p[n1].Y(), p[n1].Z() ), + netgen::Point3d( p[n2].X(), p[n2].Y(), p[n2].Z() ), + sizeCoef * minSize ); + } + else + { + gp_XY uvVec( uv[n2] - uv[n1] ); + double len = ( p[n1] - p[n2] ).Modulus(); + int nb = int( len / minSize ) + 1; + for ( int j = 0; j <= nb; ++j ) + { + double r = double( j ) / nb; + gp_XY uvj = uv[n1] + r * uvVec; + + surfProp.SetParameters( uvj.X(), uvj.Y() ); + double maxCurv = Max( Abs( surfProp.MaxCurvature()), Abs( surfProp.MinCurvature() )); + double h = elemSizeForChordalError( _chordalError, 1 / maxCurv ); + + const gp_Pnt& pj = surfProp.Value(); + netgen::Point3d ngP( pj.X(), pj.Y(), pj.Z()); + ngMesh.RestrictLocalH( ngP, h * sizeCoef ); + } + } + } + } + } + } } //================================================================================ @@ -2724,6 +2897,7 @@ bool NETGENPlugin_Mesher::Compute() { // Local size on shapes SetLocalSize( occgeo, *_ngMesh ); + SetLocalSizeForChordalError( occgeo, *_ngMesh ); } // Precompute internal edges (issue 0020676) in order to @@ -3290,25 +3464,25 @@ bool NETGENPlugin_Mesher::Evaluate(MapShapeNbElems& aResMap) sm->GetComputeError().reset( new SMESH_ComputeError( COMPERR_ALGO_FAILED )); return false; } - if ( _simpleHyp ) - { - // Pass 1D simple parameters to NETGEN - // -------------------------------- - int nbSeg = _simpleHyp->GetNumberOfSegments(); - double segSize = _simpleHyp->GetLocalLength(); - for ( int iE = 1; iE <= occgeo.emap.Extent(); ++iE ) - { - const TopoDS_Edge& e = TopoDS::Edge( occgeo.emap(iE)); - if ( nbSeg ) - segSize = SMESH_Algo::EdgeLength( e ) / ( nbSeg - 0.4 ); - setLocalSize( e, segSize, *ngMesh ); - } - } - else // if ( ! _simpleHyp ) - { - // Local size on shapes - SetLocalSize( occgeo, *ngMesh ); - } + // if ( _simpleHyp ) + // { + // // Pass 1D simple parameters to NETGEN + // // -------------------------------- + // int nbSeg = _simpleHyp->GetNumberOfSegments(); + // double segSize = _simpleHyp->GetLocalLength(); + // for ( int iE = 1; iE <= occgeo.emap.Extent(); ++iE ) + // { + // const TopoDS_Edge& e = TopoDS::Edge( occgeo.emap(iE)); + // if ( nbSeg ) + // segSize = SMESH_Algo::EdgeLength( e ) / ( nbSeg - 0.4 ); + // setLocalSize( e, segSize, *ngMesh ); + // } + // } + // else // if ( ! _simpleHyp ) + // { + // // Local size on shapes + // SetLocalSize( occgeo, *ngMesh ); + // } // calculate total nb of segments and length of edges double fullLen = 0.0; int fullNbSeg = 0; diff --git a/src/NETGENPlugin/NETGENPlugin_Mesher.hxx b/src/NETGENPlugin/NETGENPlugin_Mesher.hxx index 88e093e..608de2a 100644 --- a/src/NETGENPlugin/NETGENPlugin_Mesher.hxx +++ b/src/NETGENPlugin/NETGENPlugin_Mesher.hxx @@ -124,6 +124,8 @@ class NETGENPLUGIN_EXPORT NETGENPlugin_Mesher void SetParameters(const NETGENPlugin_SimpleHypothesis_2D* hyp); void SetParameters(const StdMeshers_ViscousLayers* hyp ); void SetViscousLayers2DAssigned(bool isAssigned) { _isViscousLayers2D = isAssigned; } + + void SetLocalSizeForChordalError( netgen::OCCGeometry& occgeo, netgen::Mesh& ngMesh ); static void SetLocalSize( netgen::OCCGeometry& occgeo, netgen::Mesh& ngMesh ); bool Compute(); @@ -204,6 +206,7 @@ class NETGENPLUGIN_EXPORT NETGENPlugin_Mesher bool _optimize; int _fineness; bool _isViscousLayers2D; + double _chordalError; netgen::Mesh* _ngMesh; netgen::OCCGeometry* _occgeom; @@ -217,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_ONLY.cxx b/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_ONLY.cxx index 5cc5607..3e0a93f 100644 --- a/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_ONLY.cxx +++ b/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_ONLY.cxx @@ -319,6 +319,7 @@ bool NETGENPlugin_NETGEN_2D_ONLY::Compute(SMESH_Mesh& aMesh, // set local size defined on shapes aMesher.SetLocalSize( occgeoComm, *ngMeshes[0] ); + aMesher.SetLocalSizeForChordalError( occgeoComm, *ngMeshes[0] ); try { ngMeshes[0]->LoadLocalMeshSize( mparam.meshsizefilename ); } catch (NgException & ex) { @@ -460,6 +461,7 @@ bool NETGENPlugin_NETGEN_2D_ONLY::Compute(SMESH_Mesh& aMesh, bb.Increase (bb.Diam()/10); ngMesh->SetLocalH (bb.PMin(), bb.PMax(), mparam.grading); aMesher.SetLocalSize( occgeom, *ngMesh ); + aMesher.SetLocalSizeForChordalError( occgeoComm, *ngMesh ); try { ngMesh->LoadLocalMeshSize( mparam.meshsizefilename ); } catch (NgException & ex) { 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..dd36c08 --- /dev/null +++ b/src/NETGENPlugin/NETGENPlugin_Remesher_2D.cxx @@ -0,0 +1,685 @@ +// 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 + 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 + 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;