refs #254: 7.5.5. Mesh generation for semi-analytical boundaries

Add NETGEN Remesher
This commit is contained in:
eap 2017-10-19 19:53:43 +03:00
parent 1a836a25cc
commit d01b6f371f
23 changed files with 1304 additions and 251 deletions

View File

@ -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.

View File

@ -17,6 +17,10 @@ meshing 2D objects).
\image html netgen2d3d_only.png
<center><em>Dialog boxes of <b>NETGEN 2D</b> and <b>NETGEN 3D</b>
algorithms </em></center>
<br>
\image html netgen2d_remesher.png
<center><em>Hypothesis dialog box of <b>NETGEN 2D</b> remesher algorithms</em></center>
- <b>Name</b> - allows to define the name for the algorithm (NETGEN
2D (or 3D) Parameters by default).
@ -61,6 +65,9 @@ process is rather time consuming comparing to creation of initial mesh.
- <b>Fuse Coincident Nodes on Edges and Vertices</b> - allows merging
mesh nodes on vertices and edges which are geometrically coincident
but are topologically different.
- <b>Ridge angle</b> - allows to define minimum angle in degrees between
normals of adjacent triangles at which the remesher (Netgen 2D working
w/o geometry) considers the edge between these triangles as a feature edge.
\image html netgen3d_local_size.png
@ -76,7 +83,9 @@ can be changed.
- <b>Mesh-size File</b> - 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 <b>Min
Size</b> and <b>Max Size</b> bounds. Let's consider the following
sample size file.
\code
2
92.5 92.5 92.5 0.05
@ -96,6 +105,7 @@ section.<br>
Sizes defined in the file are trimmed between <b>Min Size</b> and <b>Max Size</b>
bounds.
\image html netgen2d3d_simple.png
<b>NETGEN 2D simple parameters</b> and <b>NETGEN 3D simple
@ -133,6 +143,7 @@ close edges influence each other.
- The local size of segments influences the size of close triangles.
- The order of elements and their size in the 1D mesh generated by
NETGEN differ from those in the 1D mesh generated by Regular_1D
algorithm, resulting in different 2D and 3D meshes.
algorithm, which results in different 2D and 3D meshes at the same 1D
input parameters.
*/

View File

@ -66,6 +66,14 @@ module NETGENPlugin
{
};
/*!
* NETGENPlugin_Remesher_2D: interface of "NETGEN Remesher" algorithm,
* generating 2D elements basing on an existing 2D mesh
*/
interface NETGENPlugin_Remesher_2D : SMESH::SMESH_2D_Algo
{
};
/*!
* NETGENPlugin_Hypothesis: interface of "NETGEN parameters" hypothesis
*/
@ -92,14 +100,14 @@ module NETGENPlugin
void SetNbSegPerEdge(in double value);
double GetNbSegPerEdge();
void SetNbSegPerRadius(in double value);
double GetNbSegPerRadius();
void SetChordalErrorEnabled(in boolean value);
boolean GetChordalErrorEnabled();
void SetChordalError(in double value);
double GetChordalError();
void SetNbSegPerRadius(in double value);
double GetNbSegPerRadius();
void SetQuadAllowed(in boolean value);
boolean GetQuadAllowed();
@ -141,6 +149,18 @@ module NETGENPlugin
{
};
/*!
* interface of "NETGEN Remesher parameters" hypothesis used by NETGENPlugin_Remesher_2D algoritm
*/
interface NETGENPlugin_RemesherHypothesis_2D : NETGENPlugin_Hypothesis_2D
{
/*!
* \brief Set/get ridge angle
*/
void SetRidgeAngle(in double angle );
double GetRidgeAngle();
};
/*!
* NETGENPlugin_Hypothesis: interface of "NETGEN 2D simple parameters" hypothesis
*/

View File

@ -45,6 +45,7 @@
</accumulative-methods>
</python-wrap>
</hypothesis>
<hypothesis type ="NETGEN_Parameters_2D"
label-id="NETGEN 2D Parameters"
icon-id ="mesh_hypo_netgen_2d.png"
@ -56,6 +57,7 @@
</accumulative-methods>
</python-wrap>
</hypothesis>
<hypothesis type ="NETGEN_Parameters_3D"
label-id="NETGEN 3D Parameters"
icon-id ="mesh_hypo_netgen.png"
@ -67,6 +69,7 @@
</accumulative-methods>
</python-wrap>
</hypothesis>
<hypothesis type ="NETGEN_Parameters_2D_ONLY"
label-id="NETGEN 2D Parameters"
icon-id ="mesh_hypo_netgen_2d.png"
@ -78,10 +81,17 @@
</accumulative-methods>
</python-wrap>
</hypothesis>
<hypothesis type ="NETGEN_RemesherParameters_2D"
label-id="NETGEN 2D Parameters"
icon-id ="mesh_hypo_netgen_2d.png"
dim ="2"/>
<hypothesis type ="NETGEN_SimpleParameters_2D"
label-id="NETGEN 2D Simple Parameters"
icon-id ="mesh_hypo_netgen_2d.png"
dim ="2"/>
<hypothesis type ="NETGEN_SimpleParameters_3D"
label-id="NETGEN 3D Simple Parameters"
icon-id ="mesh_hypo_netgen.png"
@ -162,6 +172,19 @@
</python-wrap>
</algorithm>
<algorithm type ="NETGEN_Remesher_2D"
label-id ="NETGEN 2D"
icon-id ="mesh_algo_netgen_2d.png"
opt-hypos ="NETGEN_RemesherParameters_2D"
output ="TRIA,QUAD"
need-geom ="never"
dim ="2">
<python-wrap>
<algo>NETGEN_Remesher_2D=Triangle(algo=smeshBuilder.NETGEN)</algo>
<hypo>NETGEN_RemesherParameters_2D=Parameters()</hypo>
</python-wrap>
</algorithm>
</algorithms>
</meshers-group>

View File

@ -44,7 +44,8 @@ extern "C"
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_Parameters_3D" || // 3D
aHypType=="NETGEN_RemesherParameters_2D" ) // 2D
{
aCreator = new NETGENPluginGUI_HypothesisCreator( aHypType );
}

View File

@ -92,9 +92,11 @@ NETGENPluginGUI_HypothesisCreator::NETGENPluginGUI_HypothesisCreator( const QStr
{
myGeomSelectionTools = NULL;
myLocalSizeMap.clear();
myIs2D = ( theHypType.startsWith("NETGEN_Parameters_2D"));
myIs2D = ( theHypType.startsWith("NETGEN_Parameters_2D") ||
theHypType == "NETGEN_RemesherParameters_2D");
myIsONLY = ( theHypType == "NETGEN_Parameters_2D_ONLY" ||
theHypType == "NETGEN_Parameters_3D");
theHypType == "NETGEN_Parameters_3D" ||
theHypType == "NETGEN_RemesherParameters_2D");
}
NETGENPluginGUI_HypothesisCreator::~NETGENPluginGUI_HypothesisCreator()
@ -116,6 +118,8 @@ bool NETGENPluginGUI_HypothesisCreator::checkParams(QString& msg) const
res = myNbSegPerEdge->isValid(msg,true) && res;
if ( myNbSegPerRadius )
res = myNbSegPerRadius->isValid(msg,true) && res;
if ( myRidgeAngle )
res = myRidgeAngle->isValid(msg,true) && res;
if ( !res ) // -- issue 0021364: Dump of netgen parameters has duplicate lines
storeParamsToHypo( data_old );
@ -125,6 +129,8 @@ bool NETGENPluginGUI_HypothesisCreator::checkParams(QString& msg) const
QFrame* NETGENPluginGUI_HypothesisCreator::buildFrame()
{
const bool isRemesher = ( hypType() == "NETGEN_RemesherParameters_2D" );
QFrame* fr = new QFrame( 0 );
fr->setObjectName( "myframe" );
QVBoxLayout* lay = new QVBoxLayout( fr );
@ -210,7 +216,7 @@ QFrame* NETGENPluginGUI_HypothesisCreator::buildFrame()
myChordalErrorEnabled = 0;
myChordalError = 0;
if ( myIs2D || !myIsONLY )
if (( myIs2D && !isRemesher ) || !myIsONLY )
{
myChordalErrorEnabled = new QCheckBox( tr( "NETGEN_CHORDAL_ERROR" ), GroupC1 );
aGroupLayout->addWidget( myChordalErrorEnabled, row, 0 );
@ -221,8 +227,18 @@ QFrame* NETGENPluginGUI_HypothesisCreator::buildFrame()
row++;
}
myRidgeAngle = 0;
if ( isRemesher )
{
aGroupLayout->addWidget( new QLabel( tr( "NETGEN_RIDGE_ANGLE" ), GroupC1 ), row, 0 );
myRidgeAngle = new SMESHGUI_SpinBox( GroupC1 );
myRidgeAngle->RangeStepAndValidator( 0, 90, 10, "angle_precision" );
aGroupLayout->addWidget( myRidgeAngle, row, 1 );
row++;
}
mySurfaceCurvature = 0;
if ( myIs2D || !myIsONLY )
if (( myIs2D && !isRemesher ) || !myIsONLY )
{
mySurfaceCurvature = new QCheckBox( tr( "NETGEN_SURFACE_CURVATURE" ), GroupC1 );
aGroupLayout->addWidget( mySurfaceCurvature, row, 0, 1, 2 );
@ -238,9 +254,13 @@ QFrame* NETGENPluginGUI_HypothesisCreator::buildFrame()
row++;
}
myOptimize = 0;
if ( !isRemesher )
{
myOptimize = new QCheckBox( tr( "NETGEN_OPTIMIZE" ), GroupC1 );
aGroupLayout->addWidget( myOptimize, row, 0, 1, 2 );
row++;
}
myFuseEdges = 0;
if ( !myIsONLY )
@ -359,6 +379,13 @@ void NETGENPluginGUI_HypothesisCreator::retrieveParams() const
myChordalError->setText( data.myChordalErrorVar );
myChordalError->setEnabled( myChordalErrorEnabled->isChecked() );
}
if ( myRidgeAngle )
{
if ( data.myRidgeAngleVar.isEmpty() )
myRidgeAngle->setValue( data.myRidgeAngle );
else
myRidgeAngle->setText( data.myRidgeAngleVar );
}
if (myAllowQuadrangles)
myAllowQuadrangles->setChecked( data.myAllowQuadrangles );
@ -403,26 +430,26 @@ QString NETGENPluginGUI_HypothesisCreator::storeParams() const
readParamsFromWidgets( data );
storeParamsToHypo( data );
QString valStr = tr("NETGEN_MAX_SIZE") + " = " + QString::number( data.myMaxSize ) + "; ";
valStr += tr("NETGEN_MIN_SIZE") + " = " + QString::number( data.myMinSize ) + "; ";
if ( data.mySecondOrder )
valStr += tr("NETGEN_SECOND_ORDER") + "; ";
if ( data.myOptimize )
valStr += tr("NETGEN_OPTIMIZE") + "; ";
valStr += myFineness->currentText() + "(" + QString::number( data.myGrowthRate ) + ", " +
QString::number( data.myNbSegPerEdge ) + ", " +
QString::number( data.myNbSegPerRadius ) + ")";
// QString valStr = tr("NETGEN_MAX_SIZE") + " = " + QString::number( data.myMaxSize ) + "; ";
// valStr += tr("NETGEN_MIN_SIZE") + " = " + QString::number( data.myMinSize ) + "; ";
// if ( data.mySecondOrder )
// valStr += tr("NETGEN_SECOND_ORDER") + "; ";
// if ( data.myOptimize )
// valStr += tr("NETGEN_OPTIMIZE") + "; ";
// valStr += myFineness->currentText() + "(" + QString::number( data.myGrowthRate ) + ", " +
// QString::number( data.myNbSegPerEdge ) + ", " +
// QString::number( data.myNbSegPerRadius ) + ")";
if ( myIs2D && data.myAllowQuadrangles )
valStr += "; " + tr("NETGEN_ALLOW_QUADRANGLES");
// if ( myIs2D && data.myAllowQuadrangles )
// valStr += "; " + tr("NETGEN_ALLOW_QUADRANGLES");
if ( data.mySurfaceCurvature )
valStr += "; " + tr("NETGEN_SURFACE_CURVATURE");
// if ( data.mySurfaceCurvature )
// valStr += "; " + tr("NETGEN_SURFACE_CURVATURE");
if ( data.myFuseEdges )
valStr += "; " + tr("NETGEN_FUSE_EDGES");
// if ( data.myFuseEdges )
// valStr += "; " + tr("NETGEN_FUSE_EDGES");
return valStr;
return QString();
}
bool NETGENPluginGUI_HypothesisCreator::readParamsFromHypo( NetgenHypothesisData& h_data ) const
@ -455,12 +482,20 @@ bool NETGENPluginGUI_HypothesisCreator::readParamsFromHypo( NetgenHypothesisData
//if ( myIs2D )
{
NETGENPlugin::NETGENPlugin_Hypothesis_var h =
NETGENPlugin::NETGENPlugin_Hypothesis::_narrow( initParamsHypothesis() );
// NETGENPlugin::NETGENPlugin_Hypothesis_var h =
// NETGENPlugin::NETGENPlugin_Hypothesis::_narrow( initParamsHypothesis() );
if ( !h->_is_nil() )
h_data.myAllowQuadrangles = h->GetQuadAllowed();
}
if ( myIs2D )
{
NETGENPlugin::NETGENPlugin_RemesherHypothesis_2D_var rh =
NETGENPlugin::NETGENPlugin_RemesherHypothesis_2D::_narrow( h );
if ( !rh->_is_nil() )
h_data.myRidgeAngle = rh->GetRidgeAngle();
}
NETGENPluginGUI_HypothesisCreator* that = (NETGENPluginGUI_HypothesisCreator*)this;
NETGENPlugin::string_array_var myEntries = h->GetLocalSizeEntries();
@ -496,7 +531,9 @@ 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 );
if ( mySecondOrder )
h->SetSecondOrder ( h_data.mySecondOrder );
if ( myOptimize )
h->SetOptimize ( h_data.myOptimize );
int fineness = h_data.myFineness;
h->SetFineness ( fineness );
@ -505,17 +542,28 @@ bool NETGENPluginGUI_HypothesisCreator::storeParamsToHypo( const NetgenHypothesi
{
h->SetVarParameter ( h_data.myGrowthRateVar.toLatin1().constData(), "SetGrowthRate");
h->SetGrowthRate ( h_data.myGrowthRate );
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 );
if ( mySurfaceCurvature )
h->SetUseSurfaceCurvature( h_data.mySurfaceCurvature );
if ( myFuseEdges )
h->SetFuseEdges ( h_data.myFuseEdges );
h->SetMeshSizeFile ( h_data.myMeshSizeFile.toUtf8().constData() );
@ -523,15 +571,23 @@ bool NETGENPluginGUI_HypothesisCreator::storeParamsToHypo( const NetgenHypothesi
{
// NETGENPlugin::NETGENPlugin_Hypothesis_2D_var h_2d =
// NETGENPlugin::NETGENPlugin_Hypothesis_2D::_narrow( h );
// if ( !h_2d->_is_nil() )
// h_2d->SetQuadAllowed( h_data.myAllowQuadrangles );
if ( myAllowQuadrangles )
h->SetQuadAllowed( h_data.myAllowQuadrangles );
}
QMapIterator<QString,QString> i(myLocalSizeMap);
while (i.hasNext()) {
i.next();
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<QString,QString> i(myLocalSizeMap); i.hasNext(); i.next() )
{
const QString entry = i.key();
const QString localSize = i.value();
if (localSize == "__TO_DELETE__")
@ -540,10 +596,7 @@ bool NETGENPluginGUI_HypothesisCreator::storeParamsToHypo( const NetgenHypothesi
}
else
{
std::istringstream tmp(localSize.toLatin1().constData());
double val;
tmp >> val;
h->SetLocalSizeOnEntry(entry.toLatin1().constData(), val);
h->SetLocalSizeOnEntry(entry.toLatin1().constData(), localSize.toDouble());
}
}
}
@ -584,6 +637,11 @@ bool NETGENPluginGUI_HypothesisCreator::readParamsFromWidgets( NetgenHypothesisD
h_data.myChordalError = myChordalError->value();
h_data.myChordalErrorEnabled = myChordalError->isEnabled();
}
if ( myRidgeAngle )
{
h_data.myRidgeAngleVar = myRidgeAngle->text();
h_data.myRidgeAngle = myRidgeAngle->value();
}
if ( myAllowQuadrangles )
h_data.myAllowQuadrangles = myAllowQuadrangles->isChecked();
@ -819,18 +877,20 @@ GeomSelectionTools* NETGENPluginGUI_HypothesisCreator::getGeomSelectionTools()
QString NETGENPluginGUI_HypothesisCreator::caption() const
{
return tr( QString( "NETGEN_%1_TITLE" ).arg(myIs2D?QString("2D"):QString("3D")).toLatin1().data() );
return tr( myIs2D ? "NETGEN_2D_TITLE" : "NETGEN_3D_TITLE");
}
QPixmap NETGENPluginGUI_HypothesisCreator::icon() const
{
QString hypIconName = tr( QString("ICON_DLG_NETGEN_PARAMETERS%1").arg(myIs2D?QString("_2D"):QString("")).toLatin1().data() );
QString hypIconName = tr( myIs2D ?
"ICON_DLG_NETGEN_PARAMETERS_2D" :
"ICON_DLG_NETGEN_PARAMETERS");
return SUIT_Session::session()->resourceMgr()->loadPixmap( "NETGENPlugin", hypIconName );
}
QString NETGENPluginGUI_HypothesisCreator::type() const
{
return tr( QString( "NETGEN_%1_HYPOTHESIS" ).arg(myIs2D?QString("2D"):QString("3D")).toLatin1().data() );
return tr( myIs2D ? "NETGEN_2D_HYPOTHESIS" : "NETGEN_3D_HYPOTHESIS");
}
QString NETGENPluginGUI_HypothesisCreator::helpPage() const

View File

@ -44,11 +44,11 @@ class QTableWidget;
typedef struct
{
double myMaxSize, myMinSize, myGrowthRate, myNbSegPerEdge, myNbSegPerRadius, myChordalError;
double myMaxSize, myMinSize, myGrowthRate, myNbSegPerEdge, myNbSegPerRadius, myRidgeAngle, myChordalError;
int myFineness;
bool mySecondOrder, myAllowQuadrangles, myOptimize, mySurfaceCurvature, myFuseEdges, myChordalErrorEnabled;
QString myName, myMeshSizeFile;
QString myMaxSizeVar, myMinSizeVar, myGrowthRateVar, myNbSegPerEdgeVar, myNbSegPerRadiusVar, myChordalErrorVar;
QString myMaxSizeVar, myMinSizeVar, myGrowthRateVar, myNbSegPerEdgeVar, myNbSegPerRadiusVar, myRidgeAngleVar, myChordalErrorVar;
} NetgenHypothesisData;
/*!
@ -103,6 +103,7 @@ private:
SMESHGUI_SpinBox* myGrowthRate;
SMESHGUI_SpinBox* myNbSegPerEdge;
SMESHGUI_SpinBox* myNbSegPerRadius;
SMESHGUI_SpinBox* myRidgeAngle;
QCheckBox* myChordalErrorEnabled;
SMESHGUI_SpinBox* myChordalError;
QCheckBox* myAllowQuadrangles;

View File

@ -95,6 +95,14 @@
<source>NETGEN_CHORDAL_ERROR</source>
<translation>Chordal Error</translation>
</message>
<message>
<source>NETGEN_CHORDAL_ERROR</source>
<translation>Chordal Error</translation>
</message>
<message>
<source>NETGEN_RIDGE_ANGLE</source>
<translation>Ridge Angle</translation>
</message>
<message>
<source>NETGEN_SURFACE_CURVATURE</source>
<translation>Limit Size by Surface Curvature</translation>

View File

@ -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
)

View File

@ -106,6 +106,10 @@ class NETGEN_Algorithm(Mesh_Algorithm):
def __init__(self, mesh, geom=0):
Mesh_Algorithm.__init__(self)
if noNETGENPlugin: print "Warning: NETGENPlugin module unavailable"
if not mesh.GetMesh().HasShapeToMesh() and \
self.meshMethod == "Triangle": # create a 2D remesher
self.Create(mesh, geom, "NETGEN_Remesher_2D", LIBRARY)
else:
self.Create(mesh, geom, self.algoType, LIBRARY)
self.params = None
pass
@ -161,6 +165,9 @@ class NETGEN_Algorithm(Mesh_Algorithm):
else:
hypType = "NETGEN_Parameters_3D"
if self.algo.GetName() == "NETGEN_Remesher_2D":
hypType = "NETGEN_RemesherParameters_2D"
if self.params and self.params.GetName() != hypType:
self.mesh.RemoveHypothesis( self.params, self.geom )
self.params = None
@ -229,6 +236,21 @@ class NETGEN_1D2D3D_Algorithm(NETGEN_Algorithm):
self.params.SetChordalErrorEnabled( theVal > 0 )
pass
## Sets @c ChordalError parameter
# @param theVal new value of the @c ChordalError parameter
def SetChordalError(self, theVal):
if self.Parameters():
self.params.SetChordalError(theVal)
self.params.SetChordalErrorEnabled( theVal > 0 )
pass
## Sets @c RidgeAngle parameter
# @param theVal new value of the @c RidgeAngle parameter
def SetRidgeAngle(self, theVal):
if self.Parameters():
self.params.SetRidgeAngle(theVal)
pass
## Sets @c QuadAllowed flag
# @param toAllow new value of the @c QuadAllowed parameter (@c True by default)
def SetQuadAllowed(self, toAllow=True):

View File

@ -122,10 +122,8 @@ public:
static bool GetDefaultFuseEdges();
// Persistence
virtual ostream & SaveTo(ostream & save);
virtual istream & LoadFrom(istream & load);
friend NETGENPLUGIN_EXPORT ostream & operator <<(ostream & save, NETGENPlugin_Hypothesis & hyp);
friend NETGENPLUGIN_EXPORT istream & operator >>(istream & load, NETGENPlugin_Hypothesis & hyp);
virtual std::ostream & SaveTo(std::ostream & save);
virtual std::istream & LoadFrom(std::istream & load);
/*!
* \brief Does nothing

View File

@ -28,7 +28,6 @@
//=============================================================================
//
#include "NETGENPlugin_Hypothesis_2D.hxx"
#include <utilities.h>
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();
// }
// }
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;
// //=============================================================================
// /*!
// *
// */
// //=============================================================================
// bool NETGENPlugin_Hypothesis_2D::GetDefaultQuadAllowed()
// {
// return false;
// }
_ridgeAngle = DefaultRidgeAngle();
}
// //=============================================================================
// /*!
// *
// */
// //=============================================================================
// ostream & NETGENPlugin_Hypothesis_2D::SaveTo(ostream & save)
// {
// NETGENPlugin_Hypothesis::SaveTo(save);
//=============================================================================
/*!
*
*/
//=============================================================================
// save << " " << (int)_quadAllowed;
void NETGENPlugin_RemesherHypothesis_2D::SetRidgeAngle( double angle )
{
if ( _ridgeAngle != angle )
{
_ridgeAngle = angle;
NotifySubMeshesHypothesisModification();
}
}
// return save;
// }
//=============================================================================
/*!
*
*/
//=============================================================================
// //=============================================================================
// /*!
// *
// */
// //=============================================================================
// istream & NETGENPlugin_Hypothesis_2D::LoadFrom(istream & load)
// {
// NETGENPlugin_Hypothesis::LoadFrom(load);
double NETGENPlugin_RemesherHypothesis_2D::GetRidgeAngle() const
{
return _ridgeAngle;
}
// bool isOK = true;
// int is;
//=============================================================================
/*!
*
*/
//=============================================================================
// isOK = (load >> is);
// if (isOK)
// _quadAllowed = (bool) is;
// else
// load.clear(ios::badbit | load.rdstate());
std::ostream & NETGENPlugin_RemesherHypothesis_2D::SaveTo(std::ostream & save)
{
NETGENPlugin_Hypothesis::SaveTo( save );
save << " " << _ridgeAngle;
// return load;
// }
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;
}

View File

@ -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

View File

@ -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
@ -69,36 +64,6 @@ NETGENPlugin_Hypothesis_2D_i::~NETGENPlugin_Hypothesis_2D_i()
{
}
//=============================================================================
/*!
* NETGENPlugin_Hypothesis_2D_i::SetQuadAllowed
*
* Set QuadAllowed flag
*/
//=============================================================================
// 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_i::GetQuadAllowed
*
* Get QuadAllowed flag
*/
//=============================================================================
// CORBA::Boolean NETGENPlugin_Hypothesis_2D_i::GetQuadAllowed()
// {
// return this->GetImpl()->GetQuadAllowed();
// }
//=============================================================================
/*!
* NETGENPlugin_Hypothesis_2D_i::GetImpl
@ -124,3 +89,74 @@ CORBA::Boolean NETGENPlugin_Hypothesis_2D_i::IsDimSupported( SMESH::Dimension ty
{
return type == SMESH::DIM_2D;
}
//=============================================================================
/*!
* NETGENPlugin_RemesherHypothesis_2D_i::NETGENPlugin_RemesherHypothesis_2D_i
*
* Constructor
*/
//=============================================================================
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_RemesherHypothesis_2D_i::GetImpl
*
* Get implementation
*/
//=============================================================================
::NETGENPlugin_RemesherHypothesis_2D* NETGENPlugin_RemesherHypothesis_2D_i::GetImpl()
{
return (::NETGENPlugin_RemesherHypothesis_2D*)myBaseImpl;
}
//================================================================================
/*!
* \brief Set ridge angle
*/
//================================================================================
void NETGENPlugin_RemesherHypothesis_2D_i::SetRidgeAngle( CORBA::Double angle )
{
GetImpl()->SetRidgeAngle( angle );
SMESH::TPythonDump() << _this() << ".SetRidgeAngle( " << SMESH::TVar(angle) << " )";
}
//================================================================================
/*!
* \brief Return ridge angle
*/
//================================================================================
CORBA::Double NETGENPlugin_RemesherHypothesis_2D_i::GetRidgeAngle()
{
return GetImpl()->GetRidgeAngle();
}

View File

@ -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

View File

@ -1111,8 +1111,7 @@ bool NETGENPlugin_Mesher::FillNgMesh(netgen::OCCGeometry& occgeom,
// get all nodes from connected <edges>
const bool isQuad = smDS->IsQuadratic();
//StdMeshers_FaceSide fSide( face, edges, _mesh, isForwad, isQuad, &helper ); -- master
StdMeshers_FaceSide fSide( face, edges, _mesh, isForwad, isQuad ); // -- V8_2_BR
StdMeshers_FaceSide fSide( face, edges, _mesh, isForwad, isQuad );
const vector<UVPtStruct>& points = fSide.GetUVPtStruct();
if ( points.empty() )
return false; // invalid node params?
@ -3069,8 +3068,7 @@ bool NETGENPlugin_Mesher::Compute()
helper.SetSubShape( F );
TSideVector wires =
StdMeshers_FaceSide::GetFaceWires( F, *_mesh, /*skipMediumNodes=*/true,
error, viscousMesh ); // -- V8_2_BR
// error, &helper, viscousMesh ); -- master
error, viscousMesh );
error = AddSegmentsToMesh( *_ngMesh, occgeo, wires, helper, nodeVec );
if ( !error ) error = SMESH_ComputeError::New();

View File

@ -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()
{
}

View File

@ -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

View File

@ -0,0 +1,692 @@
// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
//
// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
// File : NETGENPlugin_Remesher_2D.cxx
// Created : Thu Sep 21 16:48:46 2017
// Author : Edward AGAPOV (eap)
//
#include "NETGENPlugin_Remesher_2D.hxx"
#include "NETGENPlugin_Mesher.hxx"
#include "NETGENPlugin_Hypothesis_2D.hxx"
#include <SMDS_SetIterator.hxx>
#include <SMESHDS_Mesh.hxx>
#include <SMESH_ControlsDef.hxx>
#include <SMESH_Gen.hxx>
#include <SMESH_MeshAlgos.hxx>
#include <SMESH_MesherHelper.hxx>
#include <SMESH_subMesh.hxx>
#include <Bnd_B3d.hxx>
#include <Precision.hxx>
#include <occgeom.hpp>
#include <meshing.hpp>
//#include <stlgeom.hpp>
//#include <stltool.hxx>
#include <boost/container/flat_set.hpp>
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<const SMDS_MeshElement*> 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<double>::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<double>::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<const SMESHDS_Hypothesis*>& 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<const NETGENPlugin_RemesherHypothesis_2D*>( _hypothesis );
mesher.SetParameters( hyp );// for holeFiller
SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
HoleFiller holeFiller( theMesh );
//theHelper->SetIsQuadratic( theMesh.NbFaces( ORDER_QUADRATIC ));
// fill ngStlGeo with triangles
Bnd_B3d box;
SMDS_ElemIteratorPtr fIt = meshDS->elementsIterator( SMDSAbs_Face );
while ( fIt->more() )
{
const SMDS_MeshElement* f = fIt->next();
SMESH_NodeXYZ n1 = f->GetNode( 0 );
SMESH_NodeXYZ n2 = f->GetNode( 1 );
SMESH_NodeXYZ n3 = f->GetNode( 2 );
Ng_STL_AddTriangle( ngStlGeo,
n1.ChangeData(),
n2.ChangeData(),
n3.ChangeData() );
box.Add( n1 );
box.Add( n2 );
box.Add( n3 );
if ( f->NbNodes() > 3 )
{
n2.Set( f->GetNode( 3 ));
Ng_STL_AddTriangle( ngStlGeo,
n1.ChangeData(),
n3.ChangeData(),
n2.ChangeData());
box.Add( n2 );
}
}
// add edges
holeFiller.AddHoleBorders( ngStlGeo );
// init stl DS
Ng_Result ng_res = Ng_STL_InitSTLGeometry( ngStlGeo );
if ( ng_res != NG_OK )
{
#ifdef _DEBUG_
holeFiller.KeepHole();
#endif
std::string txt = "Error Initialising the STL Geometry";
// if ( !stlTopo->GetStatusText().empty() )
// txt += ". " + stlTopo->GetStatusText();
return error( COMPERR_BAD_INPUT_MESH, txt );
}
Ng_Meshing_Parameters ngParams;
ng_res = Ng_STL_MakeEdges( ngStlGeo, ngLib._ngMesh, &ngParams );
if ( ng_res != NG_OK )
return error( "Error in Edge Meshing" );
// set parameters
if ( hyp )
{
ngParams.maxh = hyp->GetMaxSize();
ngParams.minh = hyp->GetMinSize();
ngParams.meshsize_filename = (char*) hyp->GetMeshSizeFile().c_str();
ngParams.quad_dominated = hyp->GetQuadAllowed();
//netgen::stlparam.yangle = hyp->GetRidgeAngle();
mesher.SetParameters( hyp );
}
else
{
double diagSize = Sqrt( box.SquareExtent() );
netgen::mparam.maxh = diagSize / GetGen()->GetBoundaryBoxSegmentation();
netgen::mparam.minh = netgen::mparam.maxh;
}
double h = netgen::mparam.maxh;
gp_XYZ pMin = box.CornerMin() - gp_XYZ(h, h, h);
gp_XYZ pMax = box.CornerMax() + gp_XYZ(h, h, h);
ngMesh->SetGlobalH( h );
ngMesh->SetMinimalH( netgen::mparam.minh );
ngMesh->SetLocalH( netgen::Point3d(pMin.X(), pMin.Y(), pMin.Z()),
netgen::Point3d(pMax.X(), pMax.Y(), pMax.Z()),
netgen::mparam.grading );
ngMesh->LoadLocalMeshSize( ngParams.meshsize_filename );
netgen::OCCGeometry occgeo;
mesher.SetLocalSize( occgeo, *ngMesh );
// meshing
try
{
ng_res = Ng_STL_GenerateSurfaceMesh( ngStlGeo, ngLib._ngMesh, &ngParams );
}
catch (netgen::NgException & ex)
{
if ( netgen::multithread.terminate )
return false;
}
if ( ng_res != NG_OK )
return error( "Error in Surface Meshing" );
int nbN = ngMesh->GetNP();
int nbE = ngMesh->GetNSeg();
int nbF = ngMesh->GetNSE();
if ( nbF == 0 )
return error( "Error in Surface Meshing" );
// remove existing mesh
SMDS_ElemIteratorPtr eIt = meshDS->elementsIterator();
while ( eIt->more() )
meshDS->RemoveFreeElement( eIt->next(), /*sm=*/0 );
SMDS_NodeIteratorPtr nIt = meshDS->nodesIterator();
while ( nIt->more() )
meshDS->RemoveFreeNode( nIt->next(), /*sm=*/0 );
// retrieve new mesh
// add nodes
std::vector< const SMDS_MeshNode* > newNodes( nbN+1 );
for ( int i = 1; i <= nbN; ++i )
{
const netgen::MeshPoint& p = ngMesh->Point(i);
newNodes[i] = meshDS->AddNode( p(0),p(1),p(2) );
}
// add edges
std::vector<const SMDS_MeshNode*> 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;
}

View File

@ -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

View File

@ -69,6 +69,8 @@ extern "C"
aCreator = new NETGENPlugin_Creator_i<NETGENPlugin_NETGEN_2D_ONLY_i>;
else if (strcmp(aHypName, "NETGEN_2D3D") == 0)
aCreator = new NETGENPlugin_Creator_i<NETGENPlugin_NETGEN_2D3D_i>;
else if (strcmp(aHypName, "NETGEN_Remesher_2D") == 0)
aCreator = new NETGENPlugin_Creator_i<NETGENPlugin_Remesher_2D_i>;
// Hypotheses
else if (strcmp(aHypName, "NETGEN_Parameters") == 0)
aCreator = new NETGENPlugin_Creator_i<NETGENPlugin_Hypothesis_i>;
@ -82,6 +84,8 @@ extern "C"
aCreator = new NETGENPlugin_Creator_i<NETGENPlugin_SimpleHypothesis_2D_i>;
else if (strcmp(aHypName, "NETGEN_SimpleParameters_3D") == 0)
aCreator = new NETGENPlugin_Creator_i<NETGENPlugin_SimpleHypothesis_3D_i>;
else if (strcmp(aHypName, "NETGEN_RemesherParameters_2D") == 0)
aCreator = new NETGENPlugin_Creator_i<NETGENPlugin_RemesherHypothesis_2D_i>;
else ;
return aCreator;