GPUSPHGUI: create a 2D remesher algo and add Chordal Error parameter

This commit is contained in:
eap 2017-10-17 17:38:39 +03:00
parent 4c519c8492
commit a7d2d23910
29 changed files with 1719 additions and 343 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

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).
@ -31,13 +35,19 @@ parameters below. You can select \a Custom to define them manually.
- <b>Growth rate</b> - allows to define how much the linear dimensions of
two adjacent cells can differ (e.g. 0.3 means 30%).
- <b>Nb. Segs per Edge</b> - allows to define the minimum number of
mesh segments in which edges will be split. This parameter is used
only if <b>Limit Size by Surface Curvature</b> is checked.
mesh segments in which edges will be split. Size of elements computed using
this value is trimmed between <b>Min Size</b> and <b>Max Size</b>
bounds. This parameter is used only if <b>Limit Size by Surface
Curvature</b> is checked.
- <b>Nb Segs per Radius</b> - 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 <b>Limit Size by
Surface Curvature</b> 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 <b>Min Size</b> and <b>Max Size</b> bounds. This parameter is
used only if <b>Limit Size by Surface Curvature</b> is checked.
- <b>Chordal Error</b> - allows to define the maximum distance between
the generated 2D element and the surface. Size of elements computed using
this criterion is trimmed between <b>Min Size</b> and <b>Max Size</b> bounds.
- <b>Limit Size by Surface Curvature</b> - if this box is checked in,
then size of mesh segments and mesh faces on curved edges and surfaces
is defined using value of <b>Nb Segs per Radius</b> parameter, and
@ -55,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
@ -70,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
@ -87,6 +102,7 @@ section.<br>
"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
<b>NETGEN 2D simple parameters</b> and <b>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.
*/

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,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
*/

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"
@ -164,6 +174,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

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

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 );
@ -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.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.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<QString,QString> 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<QString,QString> 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<int> 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

View File

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

View File

@ -91,6 +91,14 @@
<source>NETGEN_SEG_PER_RADIUS</source>
<translation>Nb. Segs per Radius</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,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):

View File

@ -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<bool>(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
}
//=============================================================================
/*!

View File

@ -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<std::string, double> 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;

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

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

View File

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

View File

@ -52,21 +52,29 @@
#include <utilities.h>
#include <BRepAdaptor_Surface.hxx>
#include <BRepBuilderAPI_Copy.hxx>
#include <BRepLProp_SLProps.hxx>
#include <BRepMesh_IncrementalMesh.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <Bnd_B3d.hxx>
#include <GeomLib_IsPlanarSurface.hxx>
#include <NCollection_Map.hxx>
#include <Poly_Triangulation.hxx>
#include <Standard_ErrorHandler.hxx>
#include <Standard_ProgramError.hxx>
#include <TColStd_MapOfInteger.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopLoc_Location.hxx>
#include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
#include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
#include <TopTools_DataMapOfShapeInteger.hxx>
#include <TopTools_DataMapOfShapeShape.hxx>
#include <TopTools_MapOfShape.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Compound.hxx>
// 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<double>::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<int,double>::const_iterator it=EdgeId2LocalSize.begin(); it!=EdgeId2LocalSize.end(); it++)
// edges
std::map<int,double>::const_iterator it;
for( it=EdgeId2LocalSize.begin(); it!=EdgeId2LocalSize.end(); it++)
{
int key = (*it).first;
double hi = (*it).second;
const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key);
setLocalSize( TopoDS::Edge(shape), hi, ngMesh );
}
for(std::map<int,double>::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<int,double>::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<int,double>::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<int> fInd;
for ( int i = 1; i <= occgeo.fmap.Extent(); ++i )
{
const TopoDS_Face& face = TopoDS::Face( occgeo.fmap( i ));
BRepAdaptor_Surface surfAd( face, false );
switch ( surfAd.GetType() )
{
case GeomAbs_Plane:
continue;
case GeomAbs_Cylinder:
case GeomAbs_Sphere:
case GeomAbs_Torus: // constant curvature
{
surfProp.SetSurface( surfAd );
surfProp.SetParameters( 0, 0 );
double maxCurv = Max( Abs( surfProp.MaxCurvature()), Abs( surfProp.MinCurvature() ));
double size = elemSizeForChordalError( _chordalError, 1 / maxCurv );
occgeo.SetFaceMaxH( i, size * sizeCoef );
// limit size one edges
TopTools_MapOfShape edgeMap;
for ( TopExp_Explorer eExp( face, TopAbs_EDGE ); eExp.More(); eExp.Next() )
if ( edgeMap.Add( eExp.Current() ))
setLocalSize( TopoDS::Edge( eExp.Current() ), size, ngMesh, /*overrideMinH=*/false );
break;
}
default:
Handle(Geom_Surface) surf = BRep_Tool::Surface( face, loc );
if ( GeomLib_IsPlanarSurface( surf ).IsPlanar() )
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;

View File

@ -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;
};
//=============================================================================

View File

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

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,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 <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
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<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;