22316: EDF 2719 SMESH: Split hexas into prisms

This commit is contained in:
eap 2014-01-20 10:31:23 +00:00
parent a406fd6793
commit f500e5a8b6
15 changed files with 1262 additions and 179 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -39,7 +39,7 @@ with consequent transformation of all adjacent elements and edges.</li>
of the selected elements.</li> of the selected elements.</li>
<li>\subpage reorient_faces_page "Reorient faces by vector".</li> <li>\subpage reorient_faces_page "Reorient faces by vector".</li>
<li>\subpage cutting_quadrangles_page "Cut a quadrangle" into two triangles.</li> <li>\subpage cutting_quadrangles_page "Cut a quadrangle" into two triangles.</li>
<li>\subpage split_to_tetra_page "Split" volumic elements into tetrahedra.</li> <li>\subpage split_to_tetra_page "Split" volumic elements into tetrahedra or prisms.</li>
<li>\subpage smoothing_page "Smooth" elements, reducung distortions in <li>\subpage smoothing_page "Smooth" elements, reducung distortions in
them by adjusting the locations of element corners.</li> them by adjusting the locations of element corners.</li>
<li>Create an \subpage extrusion_page "extrusion" along a vector.</li> <li>Create an \subpage extrusion_page "extrusion" along a vector.</li>

View File

@ -1,53 +1,86 @@
/*! /*!
\page split_to_tetra_page Splitting volumes into tetrahedra \page split_to_tetra_page Splitting volumes
\n This operation allows to split volumic elements into tetrahedra. \n This operation allows to split either any volumic elements into
2D mesh is modified accordingly. tetrahedra or hexahedra into prisms. 2D mesh is modified accordingly.
<em>To split volumes:</em> <em>To split volumes:</em>
<ol> <ol>
<li>Display a mesh or a submesh in the 3D viewer.</li> <li>Display a mesh, a sub-mesh or a group in the 3D viewer.</li>
<li>In the \b Modification menu select the <b>Split into Tetrahedra</b> item or <li>In the \b Modification menu select the <b>Split Volumes</b> item or
click <em>"Split into Tetrahedra"</em> button in the toolbar. click <em>"Split Volumes"</em> button in the toolbar.
\image html split_into_tetra_icon.png \image html split_into_tetra_icon.png
<center><em>"Split into Tetrahedra" button</em></center> <center><em>"Split Volumes" button</em></center>
The following dialog box will appear: The following dialog box will appear:
\image html split_into_tetra.png \image html split_into_tetra.png
\par <br>
<b>Target element type</b> group of radio-buttons allows to select
a type of operation. If \b Tetrahedron button is checked, then the
operation will split volumes of any type into tetrahedra.
If \b Prism button is checked, then the operation will split hexahedra
into prisms, and the dialog will look as follows:
\image html split_into_prisms.png
<ul> <ul>
<li>The main list contains the list of volumes. You can click on <li>The main list contains list of volumes to split. You can click on
a volume in the 3D viewer and it will be highlighted (lock Shift a volume in the 3D viewer and it will be highlighted (lock Shift
keyboard button to select several volumes). Click \b Add button and keyboard button to select several volumes). Click \b Add button and
the ID of this volume will be added to the list. To remove the the ID of this volume will be added to the list. To remove the
selected element or elements from the list click \b Remove button. <b>Sort selected element or elements from the list click \b Remove button. <b>Sort
list</b> button allows to sort the list of IDs. \b Filter button allows to list</b> button allows to sort the list of IDs. \b Filter button allows to
apply a definite filter to the selection of volumes. apply a definite filter to the selection of volumes.
<br><b>Note:</b> If you split not all adjacent non-tetrahedral volumes, your mesh becomes <br><b>Note:</b> If you split not all adjacent non-tetrahedral
non-conform.</li> volumes, your mesh becomes non-conform.</li>
<li><b>Apply to all</b> radio button allows to split all <li><b>Apply to all</b> radio button allows to split all
volumes of the currently displayed mesh or submesh.</li> volumes of the currently selected mesh.</li>
</ul> </ul>
<ul> <ul>
<li>\b Split hexahedron <li><b> Split hexahedron </b> group allows to specify a method of
splitting hexahedra.
<ul> <ul>
<li><b>Into 5 tetrahedra</b>, <b>Into 6 tetrahedra</b> and <b>Into 24 tetrahedra</b> allows to <li><b>Into N tetrahedra/prisms</b> allows to specify the number of
specify the number of tetrahedra a hexahedron will be split into. If the specified method does tetrahedra or prisms a hexahedron will be split into. If the
not allow to get a conform mesh, a generic solution is applied: an additional node specified method does not allow to get a conform mesh, a generic
is created at the gravity center of a hexahedron, serving an apex of tetrahedra, all quadrangle sides of the hexahedron are split into two triangles each serving a base of a new tetrahedron.</li> solution is applied: an additional node is created at the gravity
</ul> center of a hexahedron, serving an apex of tetrahedra, all
quadrangle sides of the hexahedron are split into two triangles each
serving a base of a new tetrahedron.</li>
<li> <b> Facet to split </b> group allows to specify a side (facet) of a
hexahedron to split into triangles when splitting into prisms.
The facet to split is defined by specifying a point and a direction
close to normal of the facet. The operation finds a hexahedron most
close to the specified point and splits a facet whose normal is most
close to the specified direction. Then the splitting is propagated
from that hexahedron to all adjacent hexahedra.
<ul>
<li> <b> Hexa location </b> allows to specify a <em> start
point </em> by which a first split hexahedron is found. <em>
Selection button</em> switches to selection of the element whose
barycenter will be used the start point and whose direction will be
used as a normal to facet to split into triangles. To return to
selection of volumes to split it is necessary to switch this button
off. </li>
<li> <b> Facet normal </b> allows to specify a direction of the
normal to hexahedron facet to split into triangles.</li>
</ul>
<li><b> All domains </b> - if it is off the operation stops as all
hehexedra adjacent to the start hexahedron are split into
prisms. Else the operation tries to continue splitting starting from
another hexahedron closest to the <b> Hexa location</b>. </li>
</li> </li>
</ul>
<li><b>Select from</b> a set of fields allows to choose a submesh or an <li><b>Select from</b> a set of fields allows to choose a sub-mesh or an
existing group whose elements will be automatically added to the existing group whose elements will be added to the list as you ckick
list.</li> \b Add button.</li>
</ul> </ul>
<li>Click the \b Apply or <b>Apply and Close</b> button to confirm the operation.</li> <li>Click the \b Apply or <b>Apply and Close</b> button to confirm the operation.</li>

View File

@ -323,6 +323,25 @@ module SMESH
void SplitVolumesIntoTetra(in SMESH_IDSource elems, in short methodFlags) void SplitVolumesIntoTetra(in SMESH_IDSource elems, in short methodFlags)
raises (SALOME::SALOME_Exception); raises (SALOME::SALOME_Exception);
/*!
* \brief Split hexahedra into triangular prisms
* \param elems - elements to split
* \param facetToSplitNormal - normal used to find a facet of hexahedron
* to split into triangles. Location of this vector is used to
* find a hexahedron whose facets are tested using direction of this vector.
* \param methodFlags - flags passing splitting method:
* 1 - split the hexahedron into 2 prisms
* 2 - split the hexahedron into 4 prisms
* \param allDomains - if \c False, only hexahedra adjacent to one closest
* to \a facetToSplitNormal location are split, else \a facetToSplitNormal
* is used to find the facet to split in all domains present in \a elems.
*/
void SplitHexahedraIntoPrisms(in SMESH_IDSource elems,
in short methodFlags,
in SMESH::AxisStruct facetToSplitNormal,
in boolean allDomains)
raises (SALOME::SALOME_Exception);
enum Smooth_Method { LAPLACIAN_SMOOTH, CENTROIDAL_SMOOTH }; enum Smooth_Method { LAPLACIAN_SMOOTH, CENTROIDAL_SMOOTH };

View File

@ -557,7 +557,6 @@ bool SMDS_VtkVolume::IsMediumNode(const SMDS_MeshNode* node) const
int SMDS_VtkVolume::NbCornerNodes() const int SMDS_VtkVolume::NbCornerNodes() const
{ {
vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid();
int nbN = grid->GetCell(myVtkID)->GetNumberOfPoints();
vtkIdType aVtkType = grid->GetCellType(myVtkID); vtkIdType aVtkType = grid->GetCellType(myVtkID);
switch (aVtkType) switch (aVtkType)
{ {
@ -568,7 +567,7 @@ int SMDS_VtkVolume::NbCornerNodes() const
case VTK_TRIQUADRATIC_HEXAHEDRON: return 8; case VTK_TRIQUADRATIC_HEXAHEDRON: return 8;
default:; default:;
} }
return nbN; return grid->GetCell(myVtkID)->GetNumberOfPoints();
} }
SMDSAbs_EntityType SMDS_VtkVolume::GetEntityType() const SMDSAbs_EntityType SMDS_VtkVolume::GetEntityType() const

View File

@ -1603,44 +1603,110 @@ namespace
const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3, const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 }; thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
// Methods of splitting hexahedron into prisms
const int theHexTo4Prisms_BT[6*4+1] = // bottom-top
{
0, 1, 8, 4, 5, 9, 1, 2, 8, 5, 6, 9, 2, 3, 8, 6, 7, 9, 3, 0, 8, 7, 4, 9, -1
};
const int theHexTo4Prisms_LR[6*4+1] = // left-right
{
1, 0, 8, 2, 3, 9, 0, 4, 8, 3, 7, 9, 4, 5, 8, 7, 6, 9, 5, 1, 8, 6, 2, 9, -1
};
const int theHexTo4Prisms_FB[6*4+1] = // front-back
{
0, 3, 8, 1, 2, 9, 3, 7, 8, 2, 6, 9, 7, 4, 8, 6, 5, 9, 4, 0, 8, 5, 1, 9, -1
};
const int theHexTo2Prisms_BT_1[6*2+1] =
{
0, 1, 3, 4, 5, 7, 1, 2, 3, 5, 6, 7, -1
};
const int theHexTo2Prisms_BT_2[6*2+1] =
{
0, 1, 2, 4, 5, 6, 0, 2, 3, 4, 6, 7, -1
};
const int* theHexTo2Prisms_BT[2] = { theHexTo2Prisms_BT_1, theHexTo2Prisms_BT_2 };
const int theHexTo2Prisms_LR_1[6*2+1] =
{
1, 0, 4, 2, 3, 7, 1, 4, 5, 2, 7, 6, -1
};
const int theHexTo2Prisms_LR_2[6*2+1] =
{
1, 0, 4, 2, 3, 7, 1, 4, 5, 2, 7, 6, -1
};
const int* theHexTo2Prisms_LR[2] = { theHexTo2Prisms_LR_1, theHexTo2Prisms_LR_2 };
const int theHexTo2Prisms_FB_1[6*2+1] =
{
0, 3, 4, 1, 2, 5, 3, 7, 4, 2, 6, 5, -1
};
const int theHexTo2Prisms_FB_2[6*2+1] =
{
0, 3, 7, 1, 2, 7, 0, 7, 4, 1, 6, 5, -1
};
const int* theHexTo2Prisms_FB[2] = { theHexTo2Prisms_FB_1, theHexTo2Prisms_FB_2 };
struct TTriangleFacet //!< stores indices of three nodes of tetra facet struct TTriangleFacet //!< stores indices of three nodes of tetra facet
{ {
int _n1, _n2, _n3; int _n1, _n2, _n3;
TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {} TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); } bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const; bool hasAdjacentVol( const SMDS_MeshElement* elem,
const SMDSAbs_GeometryType geom = SMDSGeom_TETRA) const;
}; };
struct TSplitMethod struct TSplitMethod
{ {
int _nbTetra; int _nbSplits;
int _nbCorners;
const int* _connectivity; //!< foursomes of tetra connectivy finished by -1 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
bool _baryNode; //!< additional node is to be created at cell barycenter bool _baryNode; //!< additional node is to be created at cell barycenter
bool _ownConn; //!< to delete _connectivity in destructor bool _ownConn; //!< to delete _connectivity in destructor
map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false) TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
: _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {} : _nbSplits(nbTet), _nbCorners(4), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; } ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
bool hasFacet( const TTriangleFacet& facet ) const bool hasFacet( const TTriangleFacet& facet ) const
{ {
const int* tetConn = _connectivity; if ( _nbCorners == 4 )
for ( ; tetConn[0] >= 0; tetConn += 4 ) {
if (( facet.contains( tetConn[0] ) + const int* tetConn = _connectivity;
facet.contains( tetConn[1] ) + for ( ; tetConn[0] >= 0; tetConn += 4 )
facet.contains( tetConn[2] ) + if (( facet.contains( tetConn[0] ) +
facet.contains( tetConn[3] )) == 3 ) facet.contains( tetConn[1] ) +
return true; facet.contains( tetConn[2] ) +
facet.contains( tetConn[3] )) == 3 )
return true;
}
else // prism, _nbCorners == 6
{
const int* prismConn = _connectivity;
for ( ; prismConn[0] >= 0; prismConn += 6 )
{
if (( facet.contains( prismConn[0] ) &&
facet.contains( prismConn[1] ) &&
facet.contains( prismConn[2] ))
||
( facet.contains( prismConn[3] ) &&
facet.contains( prismConn[4] ) &&
facet.contains( prismConn[5] )))
return true;
}
}
return false; return false;
} }
}; };
//======================================================================= //=======================================================================
/*! /*!
* \brief return TSplitMethod for the given element * \brief return TSplitMethod for the given element to split into tetrahedra
*/ */
//======================================================================= //=======================================================================
TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags) TSplitMethod getTetraSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
{ {
const int iQ = vol.Element()->IsQuadratic() ? 2 : 1; const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
@ -1665,8 +1731,8 @@ namespace
{ {
TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] ); TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] ); TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 ); if ( t012.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t012 );
else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 ); else if ( t123.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t123 );
} }
else else
{ {
@ -1679,7 +1745,7 @@ namespace
TTriangleFacet t023( nInd[ iQ * ( iCom )], TTriangleFacet t023( nInd[ iQ * ( iCom )],
nInd[ iQ * ( (iCom+2)%nbNodes )], nInd[ iQ * ( (iCom+2)%nbNodes )],
nInd[ iQ * ( (iCom+3)%nbNodes )]); nInd[ iQ * ( (iCom+3)%nbNodes )]);
if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() )) if ( t012.hasAdjacentVol( vol.Element() ) && t023.hasAdjacentVol( vol.Element() ))
{ {
triaSplits.push_back( t012 ); triaSplits.push_back( t012 );
triaSplits.push_back( t023 ); triaSplits.push_back( t023 );
@ -1719,12 +1785,12 @@ namespace
default: default:
nbVariants = 0; nbVariants = 0;
} }
for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant ) for ( int variant = 0; variant < nbVariants && method._nbSplits == 0; ++variant )
{ {
// check method compliancy with adjacent tetras, // check method compliancy with adjacent tetras,
// all found splits must be among facets of tetras described by this method // all found splits must be among facets of tetras described by this method
method = TSplitMethod( nbTet, connVariants[variant] ); method = TSplitMethod( nbTet, connVariants[variant] );
if ( hasAdjacentSplits && method._nbTetra > 0 ) if ( hasAdjacentSplits && method._nbSplits > 0 )
{ {
bool facetCreated = true; bool facetCreated = true;
for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF ) for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
@ -1738,7 +1804,7 @@ namespace
} }
} }
} }
if ( method._nbTetra < 1 ) if ( method._nbSplits < 1 )
{ {
// No standard method is applicable, use a generic solution: // No standard method is applicable, use a generic solution:
// each facet of a volume is split into triangles and // each facet of a volume is split into triangles and
@ -1832,7 +1898,7 @@ namespace
connectivity[ connSize++ ] = baryCenInd; connectivity[ connSize++ ] = baryCenInd;
} }
} }
method._nbTetra += nbTet; method._nbSplits += nbTet;
} // loop on volume faces } // loop on volume faces
@ -1842,13 +1908,132 @@ namespace
return method; return method;
} }
//=======================================================================
/*!
* \brief return TSplitMethod to split haxhedron into prisms
*/
//=======================================================================
TSplitMethod getPrismSplitMethod( SMDS_VolumeTool& vol,
const int methodFlags,
const int facetToSplit)
{
// order of facets in HEX according to SMDS_VolumeTool::Hexa_F :
// B, T, L, B, R, F
const int iF = ( facetToSplit < 2 ) ? 0 : 1 + ( facetToSplit-2 ) % 2; // [0,1,2]
if ( methodFlags == SMESH_MeshEditor::HEXA_TO_4_PRISMS )
{
static TSplitMethod to4methods[4]; // order BT, LR, FB
if ( to4methods[iF]._nbSplits == 0 )
{
switch ( iF ) {
case 0:
to4methods[iF]._connectivity = theHexTo4Prisms_BT;
to4methods[iF]._faceBaryNode[ 0 ] = 0;
to4methods[iF]._faceBaryNode[ 1 ] = 0;
break;
case 1:
to4methods[iF]._connectivity = theHexTo4Prisms_LR;
to4methods[iF]._faceBaryNode[ 2 ] = 0;
to4methods[iF]._faceBaryNode[ 4 ] = 0;
break;
case 2:
to4methods[iF]._connectivity = theHexTo4Prisms_FB;
to4methods[iF]._faceBaryNode[ 3 ] = 0;
to4methods[iF]._faceBaryNode[ 5 ] = 0;
break;
default: return to4methods[3];
}
to4methods[iF]._nbSplits = 4;
to4methods[iF]._nbCorners = 6;
}
return to4methods[iF];
}
// else if ( methodFlags == HEXA_TO_2_PRISMS )
TSplitMethod method;
const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
const int nbVariants = 2, nbSplits = 2;
const int** connVariants = 0;
switch ( iF ) {
case 0: connVariants = theHexTo2Prisms_BT; break;
case 1: connVariants = theHexTo2Prisms_LR; break;
case 2: connVariants = theHexTo2Prisms_FB; break;
default: return method;
}
// look for prisms adjacent via facetToSplit and an opposite one
for ( int is2nd = 0; is2nd < 2; ++is2nd )
{
int iFacet = is2nd ? vol.GetOppFaceIndexOfHex( facetToSplit ) : facetToSplit;
int nbNodes = vol.NbFaceNodes( iFacet ) / iQ;
if ( nbNodes != 4 ) return method;
const int* nInd = vol.GetFaceNodesIndices( iFacet );
TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
TTriangleFacet* t;
if ( t012.hasAdjacentVol( vol.Element(), SMDSGeom_PENTA ))
t = &t012;
else if ( t123.hasAdjacentVol( vol.Element(), SMDSGeom_PENTA ))
t = &t123;
else
continue;
// there are adjacent prism
for ( int variant = 0; variant < nbVariants; ++variant )
{
// check method compliancy with adjacent prisms,
// the found prism facets must be among facets of prisms described by current method
method._nbSplits = nbSplits;
method._nbCorners = 6;
method._connectivity = connVariants[ variant ];
if ( method.hasFacet( *t ))
return method;
}
}
// No adjacent prisms. Select a variant with a best aspect ratio.
double badness[2] = { 0, 0 };
static SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
const SMDS_MeshNode** nodes = vol.GetNodes();
for ( int variant = 0; variant < nbVariants; ++variant )
for ( int is2nd = 0; is2nd < 2; ++is2nd )
{
int iFacet = is2nd ? vol.GetOppFaceIndexOfHex( facetToSplit ) : facetToSplit;
const int* nInd = vol.GetFaceNodesIndices( iFacet );
method._connectivity = connVariants[ variant ];
TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
TTriangleFacet* t = ( method.hasFacet( t012 )) ? & t012 : & t123;
SMDS_FaceOfNodes tria ( nodes[ t->_n1 ],
nodes[ t->_n2 ],
nodes[ t->_n3 ] );
badness[ variant ] += getBadRate( &tria, aspectRatio );
}
const int iBetter = ( badness[1] < badness[0] && badness[0]-badness[1] > 0.1 * badness[0] );
method._nbSplits = nbSplits;
method._nbCorners = 6;
method._connectivity = connVariants[ iBetter ];
return method;
}
//================================================================================ //================================================================================
/*! /*!
* \brief Check if there is a tetraherdon adjacent to the given element via this facet * \brief Check if there is a tetraherdon adjacent to the given element via this facet
*/ */
//================================================================================ //================================================================================
bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const bool TTriangleFacet::hasAdjacentVol( const SMDS_MeshElement* elem,
const SMDSAbs_GeometryType geom ) const
{ {
// find the tetrahedron including the three nodes of facet // find the tetrahedron including the three nodes of facet
const SMDS_MeshNode* n1 = elem->GetNode(_n1); const SMDS_MeshNode* n1 = elem->GetNode(_n1);
@ -1858,16 +2043,16 @@ namespace
while ( volIt1->more() ) while ( volIt1->more() )
{ {
const SMDS_MeshElement* v = volIt1->next(); const SMDS_MeshElement* v = volIt1->next();
SMDSAbs_EntityType type = v->GetEntityType(); if ( v->GetGeomType() != geom )
if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
continue; continue;
if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 ) const int lastCornerInd = v->NbCornerNodes() - 1;
if ( v->IsQuadratic() && v->GetNodeIndex( n1 ) > lastCornerInd )
continue; // medium node not allowed continue; // medium node not allowed
const int ind2 = v->GetNodeIndex( n2 ); const int ind2 = v->GetNodeIndex( n2 );
if ( ind2 < 0 || 3 < ind2 ) if ( ind2 < 0 || lastCornerInd < ind2 )
continue; continue;
const int ind3 = v->GetNodeIndex( n3 ); const int ind3 = v->GetNodeIndex( n3 );
if ( ind3 < 0 || 3 < ind3 ) if ( ind3 < 0 || lastCornerInd < ind3 )
continue; continue;
return true; return true;
} }
@ -1900,19 +2085,23 @@ namespace
} // namespace } // namespace
//======================================================================= //=======================================================================
//function : SplitVolumesIntoTetra //function : SplitVolumes
//purpose : Split volume elements into tetrahedra. //purpose : Split volume elements into tetrahedra or prisms.
// If facet ID < 0, element is split into tetrahedra,
// else a hexahedron is split into prisms so that the given facet is
// split into triangles
//======================================================================= //=======================================================================
void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems,
const int theMethodFlags) const int theMethodFlags)
{ {
// std-like iterator on coordinates of nodes of mesh element // std-like iterator on coordinates of nodes of mesh element
typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator; typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
NXyzIterator xyzEnd; NXyzIterator xyzEnd;
SMDS_VolumeTool volTool; SMDS_VolumeTool volTool;
SMESH_MesherHelper helper( *GetMesh()); SMESH_MesherHelper helper( *GetMesh()), fHelper(*GetMesh());
fHelper.ToFixNodeParameters( true );
SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1); SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
SMESHDS_SubMesh* fSubMesh = 0;//subMesh; SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
@ -1923,29 +2112,33 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode; map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
double bc[3]; double bc[3];
TIDSortedElemSet::const_iterator elem = theElems.begin(); TFacetOfElem::const_iterator elem2facet = theElems.begin();
for ( ; elem != theElems.end(); ++elem ) for ( ; elem2facet != theElems.end(); ++elem2facet )
{ {
if ( (*elem)->GetType() != SMDSAbs_Volume ) const SMDS_MeshElement* elem = elem2facet->first;
const int facetToSplit = elem2facet->second;
if ( elem->GetType() != SMDSAbs_Volume )
continue; continue;
SMDSAbs_EntityType geomType = (*elem)->GetEntityType(); const SMDSAbs_EntityType geomType = elem->GetEntityType();
if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra ) if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
continue; continue;
if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange... if ( !volTool.Set( elem, /*ignoreCentralNodes=*/false )) continue; // strange...
TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags ); TSplitMethod splitMethod = ( facetToSplit < 0 ?
if ( splitMethod._nbTetra < 1 ) continue; getTetraSplitMethod( volTool, theMethodFlags ) :
getPrismSplitMethod( volTool, theMethodFlags, facetToSplit ));
if ( splitMethod._nbSplits < 1 ) continue;
// find submesh to add new tetras to // find submesh to add new tetras to
if ( !subMesh || !subMesh->Contains( *elem )) if ( !subMesh || !subMesh->Contains( elem ))
{ {
int shapeID = FindShape( *elem ); int shapeID = FindShape( elem );
helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
subMesh = GetMeshDS()->MeshElements( shapeID ); subMesh = GetMeshDS()->MeshElements( shapeID );
} }
int iQ; int iQ;
if ( (*elem)->IsQuadratic() ) if ( elem->IsQuadratic() )
{ {
iQ = 2; iQ = 2;
// add quadratic links to the helper // add quadratic links to the helper
@ -1963,7 +2156,8 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
iQ = 1; iQ = 1;
helper.SetIsQuadratic( false ); helper.SetIsQuadratic( false );
} }
vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() ); vector<const SMDS_MeshNode*> nodes( volTool.GetNodes(),
volTool.GetNodes() + elem->NbCornerNodes() );
helper.SetElementsOnShape( true ); helper.SetElementsOnShape( true );
if ( splitMethod._baryNode ) if ( splitMethod._baryNode )
{ {
@ -1991,16 +2185,25 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
} }
} }
// make tetras // make new volumes
vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume vector<const SMDS_MeshElement* > splitVols( splitMethod._nbSplits ); // splits of a volume
const int* tetConn = splitMethod._connectivity; const int* volConn = splitMethod._connectivity;
for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 ) if ( splitMethod._nbCorners == 4 ) // tetra
newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ], for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners )
nodes[ tetConn[1] ], newElems.Append( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ],
nodes[ tetConn[2] ], nodes[ volConn[1] ],
nodes[ tetConn[3] ])); nodes[ volConn[2] ],
nodes[ volConn[3] ]));
else // prisms
for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners )
newElems.Append( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ],
nodes[ volConn[1] ],
nodes[ volConn[2] ],
nodes[ volConn[3] ],
nodes[ volConn[4] ],
nodes[ volConn[5] ]));
ReplaceElemInGroups( *elem, tetras, GetMeshDS() ); ReplaceElemInGroups( elem, splitVols, GetMeshDS() );
// Split faces on sides of the split volume // Split faces on sides of the split volume
@ -2029,17 +2232,37 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF); map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
if ( iF_n != splitMethod._faceBaryNode.end() ) if ( iF_n != splitMethod._faceBaryNode.end() )
{ {
const SMDS_MeshNode *baryNode = iF_n->second;
for ( int iN = 0; iN < nbNodes*iQ; iN += iQ ) for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
{ {
const SMDS_MeshNode* n1 = fNodes[iN]; const SMDS_MeshNode* n1 = fNodes[iN];
const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)]; const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
const SMDS_MeshNode *n3 = iF_n->second; const SMDS_MeshNode *n3 = baryNode;
if ( !volTool.IsFaceExternal( iF )) if ( !volTool.IsFaceExternal( iF ))
swap( n2, n3 ); swap( n2, n3 );
triangles.push_back( helper.AddFace( n1,n2,n3 )); triangles.push_back( helper.AddFace( n1,n2,n3 ));
}
if ( fSubMesh && n3->getshapeId() < 1 ) if ( fSubMesh ) // update position of the bary node on geometry
fSubMesh->AddNode( n3 ); {
if ( subMesh )
subMesh->RemoveNode( baryNode, false );
GetMeshDS()->SetNodeOnFace( baryNode, fSubMesh->GetID() );
const TopoDS_Shape& s = GetMeshDS()->IndexToShape( fSubMesh->GetID() );
if ( !s.IsNull() && s.ShapeType() == TopAbs_FACE )
{
fHelper.SetSubShape( s );
gp_XY uv( 1e100, 1e100 );
double distXYZ[4];
if ( !fHelper.CheckNodeUV( TopoDS::Face( s ), baryNode,
uv, /*tol=*/1e-7, /*force=*/true, distXYZ ) &&
uv.X() < 1e100 )
{
// node is too far from the surface
GetMeshDS()->MoveNode( baryNode, distXYZ[1], distXYZ[2], distXYZ[3] );
const_cast<SMDS_MeshNode*>( baryNode )->SetPosition
( SMDS_PositionPtr( new SMDS_FacePosition( uv.X(), uv.Y() )));
}
}
} }
} }
else else
@ -2069,6 +2292,8 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
} }
} }
list< TTriangleFacet >::iterator facet = facets.begin(); list< TTriangleFacet >::iterator facet = facets.begin();
if ( facet == facets.end() )
break;
for ( ; facet != facets.end(); ++facet ) for ( ; facet != facets.end(); ++facet )
{ {
if ( !volTool.IsFaceExternal( iF )) if ( !volTool.IsFaceExternal( iF ))
@ -2087,11 +2312,11 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
} }
ReplaceElemInGroups( face, triangles, GetMeshDS() ); ReplaceElemInGroups( face, triangles, GetMeshDS() );
GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false ); GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
}
} // while a face based on facet nodes exists
} // loop on volume faces to split them into triangles } // loop on volume faces to split them into triangles
GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false ); GetMeshDS()->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false );
if ( geomType == SMDSEntity_TriQuad_Hexa ) if ( geomType == SMDSEntity_TriQuad_Hexa )
{ {
@ -2106,6 +2331,198 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
myLastCreatedElems = newElems; myLastCreatedElems = newElems;
} }
//=======================================================================
//function : GetHexaFacetsToSplit
//purpose : For hexahedra that will be split into prisms, finds facets to
// split into triangles. Only hexahedra adjacent to the one closest
// to theFacetNormal.Location() are returned.
//param [in,out] theHexas - the hexahedra
//param [in] theFacetNormal - facet normal
//param [out] theFacets - the hexahedra and found facet IDs
//=======================================================================
void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas,
const gp_Ax1& theFacetNormal,
TFacetOfElem & theFacets)
{
#define THIS_METHOD "SMESH_MeshEditor::GetHexaFacetsToSplit(): "
// Find a hexa closest to the location of theFacetNormal
const SMDS_MeshElement* startHex;
{
// get SMDS_ElemIteratorPtr on theHexas
typedef const SMDS_MeshElement* TValue;
typedef TIDSortedElemSet::iterator TSetIterator;
typedef SMDS::SimpleAccessor<TValue,TSetIterator> TAccesor;
typedef SMDS_MeshElement::GeomFilter TFilter;
typedef SMDS_SetIterator < TValue, TSetIterator, TAccesor, TFilter > TElemSetIter;
SMDS_ElemIteratorPtr elemIt = SMDS_ElemIteratorPtr
( new TElemSetIter( theHexas.begin(),
theHexas.end(),
SMDS_MeshElement::GeomFilter( SMDSGeom_HEXA )));
SMESH_ElementSearcher* searcher =
SMESH_MeshAlgos::GetElementSearcher( *myMesh->GetMeshDS(), elemIt );
startHex = searcher->FindClosestTo( theFacetNormal.Location(), SMDSAbs_Volume );
delete searcher;
if ( !startHex )
throw SALOME_Exception( THIS_METHOD "startHex not found");
}
// Select a facet of startHex by theFacetNormal
SMDS_VolumeTool vTool( startHex );
double norm[3], dot, maxDot = 0;
int facetID = -1;
for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
if ( vTool.GetFaceNormal( iF, norm[0], norm[1], norm[2] ))
{
dot = Abs( theFacetNormal.Direction().Dot( gp_Dir( norm[0], norm[1], norm[2] )));
if ( dot > maxDot )
{
facetID = iF;
maxDot = dot;
}
}
if ( facetID < 0 )
throw SALOME_Exception( THIS_METHOD "facet of startHex not found");
// Fill theFacets starting from facetID of startHex
// facets used for seach of volumes adjacent to already treated ones
typedef pair< TFacetOfElem::iterator, int > TElemFacets;
typedef map< TVolumeFaceKey, TElemFacets > TFacetMap;
TFacetMap facetsToCheck;
set<const SMDS_MeshNode*> facetNodes;
const SMDS_MeshElement* curHex;
const bool allHex = ( theHexas.size() == myMesh->NbHexas() );
while ( startHex )
{
// move in two directions from startHex via facetID
for ( int is2nd = 0; is2nd < 2; ++is2nd )
{
curHex = startHex;
int curFacet = facetID;
if ( is2nd ) // do not treat startHex twice
{
vTool.Set( curHex );
if ( vTool.IsFreeFace( curFacet, &curHex ))
{
curHex = 0;
}
else
{
vTool.GetFaceNodes( curFacet, facetNodes );
vTool.Set( curHex );
curFacet = vTool.GetFaceIndex( facetNodes );
}
}
while ( curHex )
{
// store a facet to split
if ( curHex->GetGeomType() != SMDSGeom_HEXA )
{
theFacets.insert( make_pair( curHex, -1 ));
break;
}
if ( !allHex && !theHexas.count( curHex ))
break;
pair< TFacetOfElem::iterator, bool > facetIt2isNew =
theFacets.insert( make_pair( curHex, curFacet ));
if ( !facetIt2isNew.second )
break;
// remember not-to-split facets in facetsToCheck
int oppFacet = vTool.GetOppFaceIndexOfHex( curFacet );
for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
{
if ( iF == curFacet && iF == oppFacet )
continue;
TVolumeFaceKey facetKey ( vTool, iF );
TElemFacets elemFacet( facetIt2isNew.first, iF );
pair< TFacetMap::iterator, bool > it2isnew =
facetsToCheck.insert( make_pair( facetKey, elemFacet ));
if ( !it2isnew.second )
facetsToCheck.erase( it2isnew.first ); // adjacent hex already checked
}
// pass to a volume adjacent via oppFacet
if ( vTool.IsFreeFace( oppFacet, &curHex ))
{
curHex = 0;
}
else
{
// get a new curFacet
vTool.GetFaceNodes( oppFacet, facetNodes );
vTool.Set( curHex );
curFacet = vTool.GetFaceIndex( facetNodes, /*hint=*/curFacet );
}
}
} // move in two directions from startHex via facetID
// Find a new startHex by facetsToCheck
startHex = 0;
facetID = -1;
TFacetMap::iterator fIt = facetsToCheck.begin();
while ( !startHex && fIt != facetsToCheck.end() )
{
const TElemFacets& elemFacets = fIt->second;
const SMDS_MeshElement* hex = elemFacets.first->first;
int splitFacet = elemFacets.first->second;
int lateralFacet = elemFacets.second;
facetsToCheck.erase( fIt );
fIt = facetsToCheck.begin();
vTool.Set( hex );
if ( vTool.IsFreeFace( lateralFacet, &curHex ) ||
curHex->GetGeomType() != SMDSGeom_HEXA )
continue;
if ( !allHex && !theHexas.count( curHex ))
continue;
startHex = curHex;
// find a facet of startHex to split
set<const SMDS_MeshNode*> lateralNodes;
vTool.GetFaceNodes( lateralFacet, lateralNodes );
vTool.GetFaceNodes( splitFacet, facetNodes );
int oppLateralFacet = vTool.GetOppFaceIndexOfHex( lateralFacet );
vTool.Set( startHex );
lateralFacet = vTool.GetFaceIndex( lateralNodes, oppLateralFacet );
// look for a facet of startHex having common nodes with facetNodes
// but not lateralFacet
for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
{
if ( iF == lateralFacet )
continue;
int nbCommonNodes = 0;
const SMDS_MeshNode** nn = vTool.GetFaceNodes( iF );
for ( int iN = 0, nbN = vTool.NbFaceNodes( iF ); iN < nbN; ++iN )
nbCommonNodes += facetNodes.count( nn[ iN ]);
if ( nbCommonNodes >= 2 )
{
facetID = iF;
break;
}
}
if ( facetID < 0 )
throw SALOME_Exception( THIS_METHOD "facet of a new startHex not found");
}
} // while ( startHex )
}
//======================================================================= //=======================================================================
//function : AddToSameGroups //function : AddToSameGroups
//purpose : add elemToAdd to the groups the elemInGroups belongs to //purpose : add elemToAdd to the groups the elemInGroups belongs to

View File

@ -169,11 +169,32 @@ public:
SMESH::Controls::NumericalFunctorPtr theCriterion); SMESH::Controls::NumericalFunctorPtr theCriterion);
enum SplitVolumToTetraFlags { HEXA_TO_5 = 1, HEXA_TO_6 = 2, HEXA_TO_24 = 3 };//!<arg of SplitVolumesIntoTetra() typedef std::map < const SMDS_MeshElement*, int, TIDCompare > TFacetOfElem;
//!<2nd arg of SplitVolumes()
enum SplitVolumToTetraFlags { HEXA_TO_5 = 1, // split into tetrahedra
HEXA_TO_6,
HEXA_TO_24,
HEXA_TO_2_PRISMS, // split into prisms
HEXA_TO_4_PRISMS };
/*! /*!
* \brief Split volumic elements into tetrahedra. * \brief Split volumic elements into tetrahedra or prisms.
* If facet ID < 0, element is split into tetrahedra,
* else a hexahedron is split into prisms so that the given facet is
* split into triangles
*/ */
void SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, const int theMethodFlags); void SplitVolumes (const TFacetOfElem & theElems, const int theMethodFlags);
/*!
* \brief For hexahedra that will be split into prisms, finds facets to
* split into triangles
* \param [in,out] theHexas - the hexahedra
* \param [in] theFacetNormal - facet normal
* \param [out] theFacets - the hexahedra and found facet IDs
*/
void GetHexaFacetsToSplit( TIDSortedElemSet& theHexas,
const gp_Ax1& theFacetNormal,
TFacetOfElem & theFacets);
enum SmoothMethod { LAPLACIAN = 0, CENTROIDAL }; enum SmoothMethod { LAPLACIAN = 0, CENTROIDAL };

View File

@ -2668,7 +2668,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID )
else if ( theCommandID == 410 ) else if ( theCommandID == 410 )
aDlg = new SMESHGUI_UnionOfTrianglesDlg(this); aDlg = new SMESHGUI_UnionOfTrianglesDlg(this);
else if ( theCommandID == 419 ) else if ( theCommandID == 419 )
aDlg = new SMESHGUI_CuttingIntoTetraDlg(this); aDlg = new SMESHGUI_SplitVolumesDlg(this);
else else
aDlg = new SMESHGUI_CuttingOfQuadsDlg(this); aDlg = new SMESHGUI_CuttingOfQuadsDlg(this);

View File

@ -36,9 +36,12 @@
#include "SMESHGUI_SpinBox.h" #include "SMESHGUI_SpinBox.h"
#include "SMESHGUI_MeshEditPreview.h" #include "SMESHGUI_MeshEditPreview.h"
#include <SMESH_Actor.h> #include "SMDS_Mesh.hxx"
#include <SMESH_TypeFilter.hxx> #include "SMDS_MeshNode.hxx"
#include <SMDS_Mesh.hxx> #include "SMDS_VolumeTool.hxx"
#include "SMESH_Actor.h"
#include "SMESH_MeshAlgos.hxx"
#include "SMESH_TypeFilter.hxx"
// SALOME GUI includes // SALOME GUI includes
#include <SUIT_Desktop.h> #include <SUIT_Desktop.h>
@ -58,9 +61,11 @@
#include <VTKViewer_CellLocationsArray.h> #include <VTKViewer_CellLocationsArray.h>
// OCCT includes // OCCT includes
#include <TColStd_IndexedMapOfInteger.hxx> #include <Bnd_B3d.hxx>
#include <TColStd_DataMapOfIntegerInteger.hxx> #include <TColStd_DataMapOfIntegerInteger.hxx>
#include <TColStd_IndexedMapOfInteger.hxx>
#include <TColStd_MapIteratorOfMapOfInteger.hxx> #include <TColStd_MapIteratorOfMapOfInteger.hxx>
#include <gp_Ax1.hxx>
// VTK includes // VTK includes
#include <vtkIdList.h> #include <vtkIdList.h>
@ -103,9 +108,10 @@
// Purpose : Constructor // Purpose : Constructor
//======================================================================= //=======================================================================
SMESHGUI_MultiEditDlg SMESHGUI_MultiEditDlg
::SMESHGUI_MultiEditDlg(SMESHGUI* theModule, ::SMESHGUI_MultiEditDlg(SMESHGUI* theModule,
const int theMode, const int theMode,
const bool the3d2d): const bool the3d2d,
bool theDoInit):
SMESHGUI_PreviewDlg(theModule), SMESHGUI_PreviewDlg(theModule),
mySelector(SMESH::GetViewWindow(theModule)->GetSelector()), mySelector(SMESH::GetViewWindow(theModule)->GetSelector()),
mySelectionMgr(SMESH::GetSelectionMgr(theModule)), mySelectionMgr(SMESH::GetSelectionMgr(theModule)),
@ -128,7 +134,8 @@ SMESHGUI_MultiEditDlg
aDlgLay->addWidget(aMainFrame); aDlgLay->addWidget(aMainFrame);
aDlgLay->addWidget(aBtnFrame); aDlgLay->addWidget(aBtnFrame);
Init(); if ( theDoInit )
Init();
} }
//======================================================================= //=======================================================================
@ -162,6 +169,7 @@ QWidget* SMESHGUI_MultiEditDlg::createMainFrame (QWidget* theParent, const bool
QRadioButton* aFaceRb = new QRadioButton(tr("SMESH_FACE"), aEntityTypeGrp); QRadioButton* aFaceRb = new QRadioButton(tr("SMESH_FACE"), aEntityTypeGrp);
QRadioButton* aVolumeRb = new QRadioButton(tr("SMESH_VOLUME"), aEntityTypeGrp); QRadioButton* aVolumeRb = new QRadioButton(tr("SMESH_VOLUME"), aEntityTypeGrp);
aEntityLayout->addWidget(aFaceRb); aEntityLayout->addWidget(aFaceRb);
aEntityLayout->addWidget(aVolumeRb); aEntityLayout->addWidget(aVolumeRb);
@ -226,9 +234,6 @@ QWidget* SMESHGUI_MultiEditDlg::createMainFrame (QWidget* theParent, const bool
myComboBoxFunctor->addItem(tr("ASPECTRATIO_ELEMENTS")); myComboBoxFunctor->addItem(tr("ASPECTRATIO_ELEMENTS"));
myComboBoxFunctor->addItem(tr("MINIMUMANGLE_ELEMENTS")); myComboBoxFunctor->addItem(tr("MINIMUMANGLE_ELEMENTS"));
myComboBoxFunctor->addItem(tr("SKEW_ELEMENTS")); myComboBoxFunctor->addItem(tr("SKEW_ELEMENTS"));
//myComboBoxFunctor->addItem(tr("AREA_ELEMENTS"));
//myComboBoxFunctor->addItem(tr("LENGTH2D_EDGES")); // for existing elements only
//myComboBoxFunctor->addItem(tr("MULTI2D_BORDERS")); // for existing elements only
myComboBoxFunctor->setCurrentIndex(0); myComboBoxFunctor->setCurrentIndex(0);
aCriterionLayout->addWidget(myChoiceWidget); aCriterionLayout->addWidget(myChoiceWidget);
@ -305,7 +310,7 @@ QWidget* SMESHGUI_MultiEditDlg::createButtonFrame (QWidget* theParent)
bool SMESHGUI_MultiEditDlg::isValid (const bool /*theMess*/) bool SMESHGUI_MultiEditDlg::isValid (const bool /*theMess*/)
{ {
return (!myMesh->_is_nil() && return (!myMesh->_is_nil() &&
(myListBox->count() > 0 || (myToAllChk->isChecked()/* && myActor*/))); (myListBox->count() > 0 || (myToAllChk->isChecked() && nbElemsInMesh() > 0)));
} }
//======================================================================= //=======================================================================
@ -1071,6 +1076,11 @@ bool SMESHGUI_ChangeOrientationDlg::process (SMESH::SMESH_MeshEditor_ptr theEdit
return theEditor->ReorientObject( obj ); return theEditor->ReorientObject( obj );
} }
int SMESHGUI_ChangeOrientationDlg::nbElemsInMesh()
{
return ( myFilterType = SMESH::FaceFilter ) ? myMesh->NbFaces() : myMesh->NbVolumes();
}
/*! /*!
* Class : SMESHGUI_UnionOfTrianglesDlg * Class : SMESHGUI_UnionOfTrianglesDlg
* Description : Construction of quadrangles by automatic association of triangles * Description : Construction of quadrangles by automatic association of triangles
@ -1164,38 +1174,43 @@ bool SMESHGUI_UnionOfTrianglesDlg::process (SMESH::SMESH_MeshEditor_ptr theEdito
return ok; return ok;
} }
int SMESHGUI_UnionOfTrianglesDlg::nbElemsInMesh()
{
return myMesh->NbTriangles();
}
void SMESHGUI_UnionOfTrianglesDlg::onDisplaySimulation( bool toDisplayPreview ) void SMESHGUI_UnionOfTrianglesDlg::onDisplaySimulation( bool toDisplayPreview )
{ {
if ( myPreviewCheckBox->isChecked() && toDisplayPreview ) { if ( myPreviewCheckBox->isChecked() && toDisplayPreview ) {
if ( isValid( true ) ) { if ( isValid( true ) ) {
try{ try{
SUIT_OverrideCursor aWaitCursor; SUIT_OverrideCursor aWaitCursor;
// get Ids of elements // get Ids of elements
SMESH::SMESH_IDSource_var obj; SMESH::SMESH_IDSource_var obj;
SMESH::long_array_var anElemIds = getIds( obj ); SMESH::long_array_var anElemIds = getIds( obj );
SMESH::NumericalFunctor_var aCriterion = getNumericalFunctor(); SMESH::NumericalFunctor_var aCriterion = getNumericalFunctor();
SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditPreviewer(); SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditPreviewer();
double aMaxAngle = myMaxAngleSpin->GetValue() * M_PI / 180.0; double aMaxAngle = myMaxAngleSpin->GetValue() * M_PI / 180.0;
if ( CORBA::is_nil( obj ) ) if ( CORBA::is_nil( obj ) )
aMeshEditor->TriToQuad( anElemIds.inout(), aCriterion, aMaxAngle ); aMeshEditor->TriToQuad( anElemIds.inout(), aCriterion, aMaxAngle );
else else
aMeshEditor->TriToQuadObject( obj, aCriterion, aMaxAngle ); aMeshEditor->TriToQuadObject( obj, aCriterion, aMaxAngle );
SMESH::MeshPreviewStruct_var aMeshPreviewStruct = aMeshEditor->GetPreviewData(); SMESH::MeshPreviewStruct_var aMeshPreviewStruct = aMeshEditor->GetPreviewData();
vtkProperty* aProp = vtkProperty::New(); vtkProperty* aProp = vtkProperty::New();
aProp->SetRepresentationToWireframe(); aProp->SetRepresentationToWireframe();
aProp->SetColor( 250, 0, 250 ); aProp->SetColor( 250, 0, 250 );
aProp->SetLineWidth( SMESH::GetFloat( "SMESH:element_width", 1 ) + 3 ); aProp->SetLineWidth( SMESH::GetFloat( "SMESH:element_width", 1 ) + 3 );
mySimulation->GetActor()->SetProperty( aProp ); mySimulation->GetActor()->SetProperty( aProp );
aProp->Delete(); aProp->Delete();
mySimulation->SetData( aMeshPreviewStruct._retn() ); mySimulation->SetData( aMeshPreviewStruct._retn() );
} catch ( ... ) { } catch ( ... ) {
hidePreview(); hidePreview();
} }
} else { } else {
hidePreview(); hidePreview();
@ -1279,6 +1294,12 @@ bool SMESHGUI_CuttingOfQuadsDlg::process (SMESH::SMESH_MeshEditor_ptr theEditor,
return hasObj ? theEditor->QuadToTriObject(obj, aCrit) : theEditor->QuadToTri(theIds, aCrit); return hasObj ? theEditor->QuadToTriObject(obj, aCrit) : theEditor->QuadToTri(theIds, aCrit);
} }
int SMESHGUI_CuttingOfQuadsDlg::nbElemsInMesh()
{
return myMesh->NbQuadrangles();
}
void SMESHGUI_CuttingOfQuadsDlg::onCriterionRB() void SMESHGUI_CuttingOfQuadsDlg::onCriterionRB()
{ {
if (myGroupChoice->checkedId() == 2) // Use numeric functor if (myGroupChoice->checkedId() == 2) // Use numeric functor
@ -1488,51 +1509,147 @@ void SMESHGUI_CuttingOfQuadsDlg::displayPreview()
} }
/*! /*!
* Class : SMESHGUI_CuttingIntoTetraDlg * Class : SMESHGUI_SplitVolumesDlg
* Description : Modification of orientation of faces * Description : Spliter of volumes into tetrahedra or prisms
*/ */
SMESHGUI_CuttingIntoTetraDlg::SMESHGUI_CuttingIntoTetraDlg(SMESHGUI* theModule) SMESHGUI_SplitVolumesDlg::SMESHGUI_SplitVolumesDlg(SMESHGUI* theModule)
: SMESHGUI_MultiEditDlg(theModule, SMESH::VolumeFilter, false) : SMESHGUI_MultiEditDlg(theModule, SMESH::VolumeFilter, /*the3d2d=*/true, /*doInit=*/false)
{ {
setWindowTitle(tr("CAPTION")); setWindowTitle(tr("CAPTION"));
myHelpFileName = "split_to_tetra_page.html"; myHelpFileName = "split_to_tetra_page.html";
myEntityType = 1; myEntityType = 1;
myCellSize = -1.;
// Facet selection group
myFacetSelGrp = new QGroupBox(tr("FACET_TO_SPLIT"), myCriterionGrp->parentWidget());
QGridLayout* facetSelLayout = new QGridLayout( myFacetSelGrp );
facetSelLayout->setMargin(MARGIN);
facetSelLayout->setSpacing(SPACING);
QLabel* pointLbl = new QLabel( tr("START_POINT"), myFacetSelGrp);
QLabel* normalLbl = new QLabel( tr("FACET_NORMAL"), myFacetSelGrp);
myFacetSelBtn = new QPushButton( mySubmeshBtn->icon(), "", myFacetSelGrp );
myFacetSelBtn->setCheckable( true );
QLabel* XLbl = new QLabel( tr("SMESH_X"), myFacetSelGrp);
QLabel* YLbl = new QLabel( tr("SMESH_Y"), myFacetSelGrp);
QLabel* ZLbl = new QLabel( tr("SMESH_Z"), myFacetSelGrp);
QLabel* dXLbl = new QLabel( tr("SMESH_DX"), myFacetSelGrp);
QLabel* dYLbl = new QLabel( tr("SMESH_DY"), myFacetSelGrp);
QLabel* dZLbl = new QLabel( tr("SMESH_DZ"), myFacetSelGrp);
QPushButton* axisBtn[3];
for ( int i = 0; i < 3; ++i )
{
myPointSpin[i] = new SMESHGUI_SpinBox( myFacetSelGrp );
myDirSpin [i] = new SMESHGUI_SpinBox( myFacetSelGrp );
myPointSpin[i]->RangeStepAndValidator( -1e10, 1e10, 10 );
myDirSpin [i]->RangeStepAndValidator( -1., 1., 0.1 );
myPointSpin[i]->SetValue(0.);
myDirSpin [i]->SetValue(0.);
myAxisBtn [i] = new QPushButton( QString("|| O") + char('X'+i ), myFacetSelGrp);
}
myDirSpin[2]->SetValue(1.);
myAllDomainsChk = new QCheckBox( tr("ALL_DOMAINS"), mySelGrp );
facetSelLayout->addWidget( pointLbl, 0, 0 );
facetSelLayout->addWidget( myFacetSelBtn, 0, 1 );
facetSelLayout->addWidget( XLbl, 0, 2 );
facetSelLayout->addWidget( myPointSpin[0],0, 3 );
facetSelLayout->addWidget( YLbl, 0, 4 );
facetSelLayout->addWidget( myPointSpin[1],0, 5 );
facetSelLayout->addWidget( ZLbl, 0, 6 );
facetSelLayout->addWidget( myPointSpin[2],0, 7 );
facetSelLayout->addWidget( normalLbl, 1, 0 );
facetSelLayout->addWidget( dXLbl, 1, 2 );
facetSelLayout->addWidget( myDirSpin[0], 1, 3 );
facetSelLayout->addWidget( dYLbl, 1, 4 );
facetSelLayout->addWidget( myDirSpin[1], 1, 5 );
facetSelLayout->addWidget( dZLbl, 1, 6 );
facetSelLayout->addWidget( myDirSpin[2], 1, 7 );
facetSelLayout->addWidget( myAxisBtn[0], 2, 2, 1, 2 );
facetSelLayout->addWidget( myAxisBtn[1], 2, 4, 1, 2 );
facetSelLayout->addWidget( myAxisBtn[2], 2, 6, 1, 2 );
myCriterionGrp->layout()->addWidget( myFacetSelGrp );
myCriterionGrp->layout()->addWidget( myAllDomainsChk );
//myChoiceWidget->layout()->addWidget( myAllDomainsChk );
connect( myFacetSelBtn, SIGNAL(clicked(bool)), SLOT(onFacetSelection(bool)) );
for ( int i = 0; i < 3; ++i )
{
connect( myAxisBtn [i], SIGNAL(clicked()), SLOT(onSetDir()) );
connect( myPointSpin[i], SIGNAL(valueChanged (const QString&)),
this, SLOT (updateNormalPreview(const QString&)) );
connect( myDirSpin [i], SIGNAL(valueChanged (const QString&)),
this, SLOT (updateNormalPreview(const QString&)) );
}
if ( myEntityTypeGrp )
{
myEntityTypeGrp->button(0)->setText( tr("SMESH_TETRAS"));
myEntityTypeGrp->button(1)->setText( tr("SMESH_PRISM"));
if ( QGroupBox* gb = qobject_cast< QGroupBox* >( myEntityTypeGrp->button(0)->parent() ))
gb->setTitle( tr("TARGET_ELEM_TYPE"));
}
myToAllChk->setChecked( true ); //aplly to the whole mesh by default myToAllChk->setChecked( true ); //aplly to the whole mesh by default
bool hasHexa = true;//myMesh->_is_nil() ? false : myMesh->NbHexas(); bool hasHexa = true;//myMesh->_is_nil() ? false : myMesh->NbHexas();
if ( hasHexa ) if ( hasHexa )
{ {
myGroupChoice->button(0)->setText( tr("SPLIT_HEX_TO_5_TETRA"));
myGroupChoice->button(1)->setText( tr("SPLIT_HEX_TO_6_TETRA"));
myGroupChoice->button(2)->setText( tr("SPLIT_HEX_TO_24_TETRA"));
myCriterionGrp->setTitle( tr("SPLIT_METHOD")); myCriterionGrp->setTitle( tr("SPLIT_METHOD"));
myCriterionGrp->show(); myCriterionGrp->show();
myComboBoxFunctor->hide(); myComboBoxFunctor->hide();
myChoiceWidget->show(); myChoiceWidget->show();
} }
setSelectionMode();
updateButtons(); on3d2dChanged( 0 );
Init();
} }
SMESHGUI_CuttingIntoTetraDlg::~SMESHGUI_CuttingIntoTetraDlg() SMESHGUI_SplitVolumesDlg::~SMESHGUI_SplitVolumesDlg()
{ {
} }
bool SMESHGUI_CuttingIntoTetraDlg::process (SMESH::SMESH_MeshEditor_ptr theEditor, bool SMESHGUI_SplitVolumesDlg::process (SMESH::SMESH_MeshEditor_ptr theEditor,
const SMESH::long_array& theIds, const SMESH::long_array& theIds,
SMESH::SMESH_IDSource_ptr theObj) SMESH::SMESH_IDSource_ptr theObj)
{ {
SMESH::SMESH_IDSource_wrap obj = theObj; SMESH::SMESH_IDSource_wrap obj = theObj;
if ( CORBA::is_nil( obj )) if ( CORBA::is_nil( obj ))
obj = theEditor->MakeIDSource( theIds, myEntityType ? SMESH::VOLUME : SMESH::FACE ); obj = theEditor->MakeIDSource( theIds, SMESH::VOLUME );
else else
obj->Register(); obj->Register();
try { try {
theEditor->SplitVolumesIntoTetra( obj, myGroupChoice->checkedId()+1 ); if ( isIntoPrisms() )
{
QStringList aParameters;
aParameters << myPointSpin[0]->text();
aParameters << myPointSpin[1]->text();
aParameters << myPointSpin[2]->text();
aParameters << myDirSpin[0]->text();
aParameters << myDirSpin[1]->text();
aParameters << myDirSpin[2]->text();
myMesh->SetParameters( aParameters.join(":").toLatin1().constData() );
SMESH::AxisStruct_var axis = new SMESH::AxisStruct;
axis->x = myPointSpin[0]->GetValue();
axis->y = myPointSpin[1]->GetValue();
axis->z = myPointSpin[2]->GetValue();
axis->vx = myDirSpin[0]->GetValue();
axis->vy = myDirSpin[1]->GetValue();
axis->vz = myDirSpin[2]->GetValue();
theEditor->SplitHexahedraIntoPrisms( obj, myGroupChoice->checkedId()+1,
axis, myAllDomainsChk->isChecked() );
}
else
{
theEditor->SplitVolumesIntoTetra( obj, myGroupChoice->checkedId()+1 );
}
} }
catch ( const SALOME::SALOME_Exception& S_ex ) { catch ( const SALOME::SALOME_Exception& S_ex ) {
SalomeApp_Tools::QtCatchCorbaException( S_ex ); SalomeApp_Tools::QtCatchCorbaException( S_ex );
@ -1543,3 +1660,308 @@ bool SMESHGUI_CuttingIntoTetraDlg::process (SMESH::SMESH_MeshEditor_ptr theEdito
} }
return true; return true;
} }
int SMESHGUI_SplitVolumesDlg::nbElemsInMesh()
{
return isIntoPrisms() ? myMesh->NbHexas() : myMesh->NbVolumes() - myMesh->NbTetras();
}
bool SMESHGUI_SplitVolumesDlg::isIntoPrisms()
{
return ( myEntityTypeGrp->checkedId() == 1 );
}
//================================================================================
/*!
* \brief Slot called when a target element type changes
*/
//================================================================================
void SMESHGUI_SplitVolumesDlg::on3d2dChanged(int isPrism)
{
if ( isPrism )
{
myFacetSelGrp->show();
myAllDomainsChk->show();
myGroupChoice->button(2)->hide();
myGroupChoice->button(0)->setText( tr("SPLIT_HEX_TO_2_PRISMS"));
myGroupChoice->button(1)->setText( tr("SPLIT_HEX_TO_4_PRISMS"));
}
else
{
myFacetSelGrp->hide();
myAllDomainsChk->hide();
myGroupChoice->button(2)->show();
myGroupChoice->button(0)->setText( tr("SPLIT_HEX_TO_5_TETRA"));
myGroupChoice->button(1)->setText( tr("SPLIT_HEX_TO_6_TETRA"));
myGroupChoice->button(2)->setText( tr("SPLIT_HEX_TO_24_TETRA"));
}
SMESHGUI_MultiEditDlg::on3d2dChanged( !myEntityType );
myEntityType = 1; // == VOLUME
}
//================================================================================
/*!
* \brief Set selection mode
*/
//================================================================================
void SMESHGUI_SplitVolumesDlg::setSelectionMode()
{
if ( myBusy || !isEnabled() ) return;
SMESH::RemoveFilters();
mySelectionMgr->clearFilters();
if (mySubmeshChk->isChecked()) {
if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
aViewWindow->SetSelectionMode(ActorSelection);
mySelectionMgr->installFilter(new SMESH_TypeFilter(SMESH::SUBMESH));
myFacetSelBtn->setChecked( false );
}
else if (myGroupChk->isChecked()) {
if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
aViewWindow->SetSelectionMode(ActorSelection);
mySelectionMgr->installFilter(new SMESH_TypeFilter(SMESH::GROUP));
myFacetSelBtn->setChecked( false );
}
if ( myFacetSelBtn->isChecked() )
{
// facet selection - select any element
if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
aViewWindow->SetSelectionMode( CellSelection );
myFilterType = SMESH::AllElementsFilter;
}
else
{
if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
aViewWindow->SetSelectionMode( VolumeSelection );
if ( isIntoPrisms() )
{
SMESH::SetFilter(new SMESHGUI_VolumeShapeFilter( SMDSGeom_HEXA ));
myFilterType = SMESHGUI_VolumeShapeFilter::GetId( SMDSGeom_HEXA );
}
else // to tetrahedra
{
SMESH::SetFilter(new SMESHGUI_VolumesFilter());
myFilterType = SMESH::VolumeFilter;
}
}
}
//================================================================================
/*!
* \brief SLOT called when selection changed
*/
//================================================================================
void SMESHGUI_SplitVolumesDlg::onSelectionDone()
{
if (myBusy || !isEnabled()) return;
if ( !myFacetSelBtn->isChecked() )
{
SMESHGUI_MultiEditDlg::onSelectionDone();
}
else // set point and normal by a selected element
{
const SALOME_ListIO& aList = mySelector->StoredIObjects();
int nbSel = aList.Extent();
if (nbSel > 0)
{
Handle(SALOME_InteractiveObject) anIO = aList.First();
myActor = SMESH::FindActorByEntry( anIO->getEntry() );
SMESH::SMESH_Mesh_var aSelMesh = SMESH::GetMeshByIO(anIO);
if (!aSelMesh->_is_nil())
myMesh = aSelMesh;
TColStd_IndexedMapOfInteger aMapIndex;
mySelector->GetIndex( anIO, aMapIndex );
if ( !aMapIndex.IsEmpty() )
showFacetByElement( aMapIndex(1) );
else if ( myCellSize < 0 )
showFacetByElement( 1 );
}
updateButtons();
}
}
//================================================================================
/*!
* \brief Show facet normal by a selected element
*/
//================================================================================
void SMESHGUI_SplitVolumesDlg::showFacetByElement( int elemID )
{
if ( !isIntoPrisms() || !myActor )
{
mySimulation->SetVisibility( false );
return;
}
SMDS_Mesh* mesh = myActor->GetObject()->GetMesh();
const SMDS_MeshElement* elem = mesh->FindElement( elemID );
if ( !elem ) return;
// set point XYZ by the element barycenter
gp_XYZ bc( 0,0,0 );
Bnd_B3d bbox;
SMDS_NodeIteratorPtr nIt = elem->nodeIterator();
vector< const SMDS_MeshNode* > nodes;
nodes.reserve( elem->NbNodes() );
while ( nIt->more() )
{
nodes.push_back( nIt->next() );
gp_XYZ p = SMESH_TNodeXYZ( nodes.back() );
bc += p;
bbox.Add( p );
}
bc /= nodes.size();
myPointSpin[0]->SetValue( bc.X() );
myPointSpin[1]->SetValue( bc.Y() );
myPointSpin[2]->SetValue( bc.Z() );
// set size
myCellSize = sqrt( bbox.SquareExtent() );
// set normal and size
gp_XYZ norm;
switch ( elem->GetType())
{
case SMDSAbs_Edge:
{
norm = SMESH_TNodeXYZ( nodes[1] ) - SMESH_TNodeXYZ( nodes[0] );
break;
}
case SMDSAbs_Face:
{
if ( !SMESH_MeshAlgos::FaceNormal( elem, norm, /*normalized=*/false ))
return;
break;
}
case SMDSAbs_Volume:
{
SMDS_VolumeTool vTool( elem );
vTool.SetExternalNormal();
bool freeFacetFound = false;
double n[3];
for ( int i = 0; i < vTool.NbFaces() && !freeFacetFound; ++i )
if (( freeFacetFound = vTool.IsFreeFace( i )))
vTool.GetFaceNormal( i, n[0], n[1], n[2] );
if ( !freeFacetFound )
vTool.GetFaceNormal( 0, n[0], n[1], n[2] );
norm.SetCoord( n[0], n[1], n[2] );
break;
}
default: return;
}
double size = norm.Modulus();
if ( size < 1e-20 )
return;
norm /= size;
myDirSpin[0]->SetValue( norm.X() );
myDirSpin[1]->SetValue( norm.Y() );
myDirSpin[2]->SetValue( norm.Z() );
if ( myCellSize > 0. )
updateNormalPreview();
}
//================================================================================
/*!
* \brief SLOT called when a point or a normal changes
*/
//================================================================================
void SMESHGUI_SplitVolumesDlg::updateNormalPreview(const QString&)
{
if ( myCellSize < 0. )
{
showFacetByElement( 1 );
return;
}
gp_Pnt point ( myPointSpin[0]->GetValue(),
myPointSpin[1]->GetValue(),
myPointSpin[2]->GetValue() );
gp_XYZ norm ( myDirSpin[0]->GetValue(),
myDirSpin[1]->GetValue(),
myDirSpin[2]->GetValue() );
if ( norm.Modulus() < 1e-20 )
return;
vtkUnstructuredGrid* grid = mySimulation->GetGrid();
// Initialize the preview mesh of an arrow
if ( grid->GetNumberOfPoints() == 0 )
{
mySimulation->SetArrowShapeAndNb( /*nb=*/1, /*hLen=*/0.3, /*R=*/0.1, /*start=*/0 );
}
// Compute new coordinates of the grid according to the dialog controls
gp_Ax1 axis( point, norm );
mySimulation->SetArrows( &axis, 4 * myCellSize );
mySimulation->SetVisibility(true);
}
//================================================================================
/*!
* \brief Slot called when facet selection button is clicked
*/
//================================================================================
void SMESHGUI_SplitVolumesDlg::onFacetSelection(bool isFacetSelection)
{
setSelectionMode();
onSelectionDone();
mySelGrp->setEnabled( !isFacetSelection );
}
//================================================================================
/*!
* \brief Slot called when an || axis button is clicked
*/
//================================================================================
void SMESHGUI_SplitVolumesDlg::onSetDir()
{
myDirSpin[0]->SetValue(0.);
myDirSpin[1]->SetValue(0.);
myDirSpin[2]->SetValue(0.);
int i = 0;
for ( ; i < 3; ++i )
if ( sender() == myAxisBtn[i] )
break;
if ( i == 3 )
i == 0;
myDirSpin[i]->SetValue(1.);
if ( myActor && !myMesh->_is_nil() && myMesh->NbNodes() > 0 )
{
double b[6];
myActor->GetUnstructuredGrid()->GetBounds(b);
gp_XYZ center( 0.5 * ( b[0] + b[1] ),
0.5 * ( b[2] + b[3] ),
0.5 * ( b[4] + b[5] ));
gp_XYZ point ( myPointSpin[0]->GetValue(),
myPointSpin[1]->GetValue(),
myPointSpin[2]->GetValue() );
gp_XYZ norm ( myDirSpin[0]->GetValue(),
myDirSpin[1]->GetValue(),
myDirSpin[2]->GetValue() );
gp_Vec cp( center, point );
if ( cp.Dot( norm ) < 0. )
myDirSpin[i]->SetValue(-1.);
}
updateNormalPreview();
}

View File

@ -70,7 +70,10 @@ class SMESHGUI_EXPORT SMESHGUI_MultiEditDlg : public SMESHGUI_PreviewDlg
Q_OBJECT Q_OBJECT
public: public:
SMESHGUI_MultiEditDlg( SMESHGUI*, const int, const bool = false ); SMESHGUI_MultiEditDlg( SMESHGUI* theModule,
const int theMode,
const bool the3d2d = false,
bool theDoInit = true );
virtual ~SMESHGUI_MultiEditDlg(); virtual ~SMESHGUI_MultiEditDlg();
void Init(); void Init();
@ -87,7 +90,7 @@ protected slots:
void onHelp(); void onHelp();
void onDeactivate(); void onDeactivate();
void onSelectionDone(); virtual void onSelectionDone();
void onFilterBtn(); void onFilterBtn();
void onAddBtn(); void onAddBtn();
@ -98,7 +101,7 @@ protected slots:
void onGroupChk(); void onGroupChk();
virtual void onToAllChk(); virtual void onToAllChk();
void onFilterAccepted(); void onFilterAccepted();
void on3d2dChanged(int); virtual void on3d2dChanged(int);
SMESH::NumericalFunctor_ptr getNumericalFunctor(); SMESH::NumericalFunctor_ptr getNumericalFunctor();
@ -110,11 +113,12 @@ protected:
virtual bool isValid( const bool ); virtual bool isValid( const bool );
SMESH::long_array_var getIds(SMESH::SMESH_IDSource_var& obj); SMESH::long_array_var getIds(SMESH::SMESH_IDSource_var& obj);
void updateButtons(); void updateButtons();
void setSelectionMode(); virtual void setSelectionMode();
virtual bool isIdValid( const int ) const; virtual bool isIdValid( const int ) const;
virtual bool process( SMESH::SMESH_MeshEditor_ptr, virtual bool process( SMESH::SMESH_MeshEditor_ptr,
const SMESH::long_array& , const SMESH::long_array& ,
SMESH::SMESH_IDSource_ptr obj) = 0; SMESH::SMESH_IDSource_ptr obj) = 0;
virtual int nbElemsInMesh() = 0;
int entityType(); int entityType();
protected: protected:
@ -178,6 +182,7 @@ protected:
virtual bool process( SMESH::SMESH_MeshEditor_ptr, virtual bool process( SMESH::SMESH_MeshEditor_ptr,
const SMESH::long_array& , const SMESH::long_array& ,
SMESH::SMESH_IDSource_ptr obj); SMESH::SMESH_IDSource_ptr obj);
virtual int nbElemsInMesh();
}; };
/*! /*!
@ -197,6 +202,7 @@ protected:
virtual bool process( SMESH::SMESH_MeshEditor_ptr, virtual bool process( SMESH::SMESH_MeshEditor_ptr,
const SMESH::long_array&, const SMESH::long_array&,
SMESH::SMESH_IDSource_ptr obj ); SMESH::SMESH_IDSource_ptr obj );
virtual int nbElemsInMesh();
protected slots: protected slots:
virtual void onDisplaySimulation( bool ); virtual void onDisplaySimulation( bool );
@ -221,6 +227,7 @@ protected:
virtual bool process( SMESH::SMESH_MeshEditor_ptr, virtual bool process( SMESH::SMESH_MeshEditor_ptr,
const SMESH::long_array& , const SMESH::long_array& ,
SMESH::SMESH_IDSource_ptr obj); SMESH::SMESH_IDSource_ptr obj);
virtual int nbElemsInMesh();
protected slots: protected slots:
virtual void reject(); virtual void reject();
@ -237,21 +244,45 @@ private:
}; };
/*! /*!
* Class : SMESHGUI_CuttingIntoTetraDlg * Class : SMESHGUI_SplitVolumesDlg
* Description : Split all volumes into tetrahedrons * Description : Split all volumes into tetrahedrons
*/ */
class SMESHGUI_CuttingIntoTetraDlg : public SMESHGUI_MultiEditDlg class SMESHGUI_SplitVolumesDlg : public SMESHGUI_MultiEditDlg
{ {
Q_OBJECT Q_OBJECT
public: public:
SMESHGUI_CuttingIntoTetraDlg( SMESHGUI* ); SMESHGUI_SplitVolumesDlg( SMESHGUI* );
virtual ~SMESHGUI_CuttingIntoTetraDlg(); virtual ~SMESHGUI_SplitVolumesDlg();
protected slots:
virtual void on3d2dChanged(int);
virtual void onSelectionDone();
void onFacetSelection(bool);
void onSetDir();
void updateNormalPreview(const QString& s="");
protected: protected:
virtual bool process( SMESH::SMESH_MeshEditor_ptr, virtual bool process( SMESH::SMESH_MeshEditor_ptr,
const SMESH::long_array&, const SMESH::long_array&,
SMESH::SMESH_IDSource_ptr obj ); SMESH::SMESH_IDSource_ptr obj );
virtual int nbElemsInMesh();
virtual void setSelectionMode();
void showFacetByElement( int id );
bool isIntoPrisms();
QGroupBox* myFacetSelGrp;
SMESHGUI_SpinBox* myPointSpin[3];
SMESHGUI_SpinBox* myDirSpin [3];
QPushButton* myFacetSelBtn;
QPushButton* myAxisBtn[3];
QCheckBox* myAllDomainsChk;
double myCellSize;
}; };
#endif // SMESHGUI_MULTIEDITDLG_H #endif // SMESHGUI_MULTIEDITDLG_H

View File

@ -1066,15 +1066,15 @@
</message> </message>
<message> <message>
<source>MEN_SPLIT_TO_TETRA</source> <source>MEN_SPLIT_TO_TETRA</source>
<translation>Split into Tetrahedra</translation> <translation>Split Volumes</translation>
</message> </message>
<message> <message>
<source>TOP_SPLIT_TO_TETRA</source> <source>TOP_SPLIT_TO_TETRA</source>
<translation>Split into Tetrahedra</translation> <translation>Split Volumes</translation>
</message> </message>
<message> <message>
<source>STB_SPLIT_TO_TETRA</source> <source>STB_SPLIT_TO_TETRA</source>
<translation>Split into Tetrahedra</translation> <translation>Split Volumes</translation>
</message> </message>
<message> <message>
<source>MESHERS_FILE_CANT_OPEN</source> <source>MESHERS_FILE_CANT_OPEN</source>
@ -6278,10 +6278,10 @@ It is impossible to read point coordinates from file</translation>
</message> </message>
</context> </context>
<context> <context>
<name>SMESHGUI_CuttingIntoTetraDlg</name> <name>SMESHGUI_SplitVolumesDlg</name>
<message> <message>
<source>CAPTION</source> <source>CAPTION</source>
<translation>Splitting volumes into tetrahedra</translation> <translation>Splitting volumes</translation>
</message> </message>
<message> <message>
<source>SPLIT_METHOD</source> <source>SPLIT_METHOD</source>
@ -6299,6 +6299,34 @@ It is impossible to read point coordinates from file</translation>
<source>SPLIT_HEX_TO_24_TETRA</source> <source>SPLIT_HEX_TO_24_TETRA</source>
<translation>Into 24 tetrahedra</translation> <translation>Into 24 tetrahedra</translation>
</message> </message>
<message>
<source>SPLIT_HEX_TO_2_PRISMS</source>
<translation>Into 2 prisms</translation>
</message>
<message>
<source>SPLIT_HEX_TO_4_PRISMS</source>
<translation>Into 4 Prisms</translation>
</message>
<message>
<source>TARGET_ELEM_TYPE</source>
<translation>Target element type</translation>
</message>
<message>
<source>FACET_TO_SPLIT</source>
<translation>Facet to split</translation>
</message>
<message>
<source>START_POINT</source>
<translation>Hexa location</translation>
</message>
<message>
<source>FACET_NORMAL</source>
<translation>Facet normal</translation>
</message>
<message>
<source>ALL_DOMAINS</source>
<translation>All domains</translation>
</message>
</context> </context>
<context> <context>
<name>SMESHGUI_PrecisionDlg</name> <name>SMESHGUI_PrecisionDlg</name>

View File

@ -1999,13 +1999,15 @@ void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems,
{ {
SMESH_TRY; SMESH_TRY;
initData(); initData();
prepareIdSource( elems ); prepareIdSource( elems );
SMESH::long_array_var anElementsId = elems->GetIDs();
TIDSortedElemSet elemSet;
arrayToSet( anElementsId, getMeshDS(), elemSet, SMDSAbs_Volume );
getEditor().SplitVolumesIntoTetra( elemSet, int( methodFlags )); ::SMESH_MeshEditor::TFacetOfElem elemSet;
const int noneFacet = -1;
SMDS_ElemIteratorPtr volIt = myMesh_i->GetElements( elems, SMESH::VOLUME );
while( volIt->more() )
elemSet.insert( elemSet.end(), make_pair( volIt->next(), noneFacet ));
getEditor().SplitVolumes( elemSet, int( methodFlags ));
declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute() declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
TPythonDump() << this << ".SplitVolumesIntoTetra( " TPythonDump() << this << ".SplitVolumesIntoTetra( "
@ -2014,6 +2016,66 @@ void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems,
SMESH_CATCH( SMESH::throwCorbaException ); SMESH_CATCH( SMESH::throwCorbaException );
} }
//================================================================================
/*!
* \brief Split hexahedra into triangular prisms
* \param elems - elements to split
* \param facetToSplitNormal - normal used to find a facet of hexahedron
* to split into triangles
* \param methodFlags - flags passing splitting method:
* 1 - split the hexahedron into 2 prisms
* 2 - split the hexahedron into 4 prisms
*/
//================================================================================
void SMESH_MeshEditor_i::SplitHexahedraIntoPrisms (SMESH::SMESH_IDSource_ptr elems,
CORBA::Short methodFlags,
const SMESH::AxisStruct & facetToSplitNormal,
CORBA::Boolean allDomains)
throw (SALOME::SALOME_Exception)
{
SMESH_TRY;
initData();
prepareIdSource( elems );
gp_Ax1 facetNorm( gp_Pnt( facetToSplitNormal.x,
facetToSplitNormal.y,
facetToSplitNormal.z ),
gp_Dir( facetToSplitNormal.vx,
facetToSplitNormal.vy,
facetToSplitNormal.vz ));
TIDSortedElemSet elemSet;
SMESH::long_array_var anElementsId = elems->GetIDs();
SMDS_MeshElement::GeomFilter filter( SMDSGeom_HEXA );
arrayToSet( anElementsId, getMeshDS(), elemSet, SMDSAbs_Volume, &filter );
::SMESH_MeshEditor::TFacetOfElem elemFacets;
while ( !elemSet.empty() )
{
getEditor().GetHexaFacetsToSplit( elemSet, facetNorm, elemFacets );
if ( !allDomains )
break;
::SMESH_MeshEditor::TFacetOfElem::iterator ef = elemFacets.begin();
for ( ; ef != elemFacets.end(); ++ef )
elemSet.erase( ef->first );
}
if ( methodFlags == 2 )
methodFlags = int( ::SMESH_MeshEditor::HEXA_TO_4_PRISMS );
else
methodFlags = int( ::SMESH_MeshEditor::HEXA_TO_2_PRISMS );
getEditor().SplitVolumes( elemFacets, int( methodFlags ));
declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
TPythonDump() << this << ".SplitHexahedraIntoPrisms( "
<< elems << ", " << methodFlags<< ", "
<< facetToSplitNormal<< ", " << allDomains << " )";
SMESH_CATCH( SMESH::throwCorbaException );
}
//======================================================================= //=======================================================================
//function : Smooth //function : Smooth
//purpose : //purpose :

View File

@ -233,6 +233,11 @@ public:
void SplitVolumesIntoTetra(SMESH::SMESH_IDSource_ptr elems, void SplitVolumesIntoTetra(SMESH::SMESH_IDSource_ptr elems,
CORBA::Short methodFlags) CORBA::Short methodFlags)
throw (SALOME::SALOME_Exception); throw (SALOME::SALOME_Exception);
void SplitHexahedraIntoPrisms(SMESH::SMESH_IDSource_ptr elems,
CORBA::Short methodFlags,
const SMESH::AxisStruct & facetToSplitNormal,
CORBA::Boolean allDomains)
throw (SALOME::SALOME_Exception);
CORBA::Boolean Smooth(const SMESH::long_array & IDsOfElements, CORBA::Boolean Smooth(const SMESH::long_array & IDsOfElements,
const SMESH::long_array & IDsOfFixedNodes, const SMESH::long_array & IDsOfFixedNodes,

View File

@ -73,7 +73,7 @@
## @defgroup l2_modif_invdiag Diagonal inversion of elements ## @defgroup l2_modif_invdiag Diagonal inversion of elements
## @defgroup l2_modif_unitetri Uniting triangles ## @defgroup l2_modif_unitetri Uniting triangles
## @defgroup l2_modif_changori Changing orientation of elements ## @defgroup l2_modif_changori Changing orientation of elements
## @defgroup l2_modif_cutquadr Cutting quadrangles ## @defgroup l2_modif_cutquadr Cutting elements
## @defgroup l2_modif_smooth Smoothing ## @defgroup l2_modif_smooth Smoothing
## @defgroup l2_modif_extrurev Extrusion and Revolution ## @defgroup l2_modif_extrurev Extrusion and Revolution
## @defgroup l2_modif_patterns Pattern mapping ## @defgroup l2_modif_patterns Pattern mapping
@ -307,7 +307,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
[TopAbs_IN, TopAbs_OUT, TopAbs_ON, TopAbs_UNKNOWN] = range(4) [TopAbs_IN, TopAbs_OUT, TopAbs_ON, TopAbs_UNKNOWN] = range(4)
# Methods of splitting a hexahedron into tetrahedra # Methods of splitting a hexahedron into tetrahedra
Hex_5Tet, Hex_6Tet, Hex_24Tet = 1, 2, 3 Hex_5Tet, Hex_6Tet, Hex_24Tet, Hex_2Prisms, Hex_4Prisms = 1, 2, 3, 1, 2
def __new__(cls): def __new__(cls):
global engine global engine
@ -851,11 +851,15 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
## Creates a filter from criteria ## Creates a filter from criteria
# @param criteria a list of criteria # @param criteria a list of criteria
# @param binOp binary operator used when binary operator of criteria is undefined
# @return SMESH_Filter # @return SMESH_Filter
# #
# <a href="../tui_filters_page.html#tui_filters">Example of Filters usage</a> # <a href="../tui_filters_page.html#tui_filters">Example of Filters usage</a>
# @ingroup l1_controls # @ingroup l1_controls
def GetFilterFromCriteria(self,criteria): def GetFilterFromCriteria(self,criteria, binOp=SMESH.FT_LogicalAND):
for i in range( len( criteria ) - 1 ):
if criteria[i].BinaryOp == self.EnumToLong( SMESH.FT_Undefined ):
criteria[i].BinaryOp = self.EnumToLong( binOp )
aFilterMgr = self.CreateFilterManager() aFilterMgr = self.CreateFilterManager()
aFilter = aFilterMgr.CreateFilter() aFilter = aFilterMgr.CreateFilter()
aFilter.SetCriteria(criteria) aFilter.SetCriteria(criteria)
@ -2284,6 +2288,12 @@ class Mesh:
def GetElementGeomType(self, id): def GetElementGeomType(self, id):
return self.mesh.GetElementGeomType(id) return self.mesh.GetElementGeomType(id)
## Returns the shape type of mesh element
# @return the value from SMESH::GeometryType enumeration
# @ingroup l1_meshinfo
def GetElementShape(self, id):
return self.mesh.GetElementShape(id)
## Returns the list of submesh elements IDs ## Returns the list of submesh elements IDs
# @param Shape a geom object(sub-shape) IOR # @param Shape a geom object(sub-shape) IOR
# Shape must be the sub-shape of a ShapeToMesh() # Shape must be the sub-shape of a ShapeToMesh()
@ -3026,18 +3036,54 @@ class Mesh:
return self.editor.BestSplit(IDOfQuad, self.smeshpyD.GetFunctor(theCriterion)) return self.editor.BestSplit(IDOfQuad, self.smeshpyD.GetFunctor(theCriterion))
## Splits volumic elements into tetrahedrons ## Splits volumic elements into tetrahedrons
# @param elemIDs either list of elements or mesh or group or submesh # @param elems either a list of elements or a mesh or a group or a submesh or a filter
# @param method flags passing splitting method: Hex_5Tet, Hex_6Tet, Hex_24Tet # @param method flags passing splitting method:
# Hex_5Tet - split the hexahedron into 5 tetrahedrons, etc # smesh.Hex_5Tet, smesh.Hex_6Tet, smesh.Hex_24Tet.
# smesh.Hex_5Tet - to split the hexahedron into 5 tetrahedrons, etc.
# @ingroup l2_modif_cutquadr # @ingroup l2_modif_cutquadr
def SplitVolumesIntoTetra(self, elemIDs, method=smeshBuilder.Hex_5Tet ): def SplitVolumesIntoTetra(self, elems, method=smeshBuilder.Hex_5Tet ):
unRegister = genObjUnRegister() unRegister = genObjUnRegister()
if isinstance( elemIDs, Mesh ): if isinstance( elems, Mesh ):
elemIDs = elemIDs.GetMesh() elems = elems.GetMesh()
if ( isinstance( elemIDs, list )): if ( isinstance( elems, list )):
elemIDs = self.editor.MakeIDSource(elemIDs, SMESH.VOLUME) elems = self.editor.MakeIDSource(elems, SMESH.VOLUME)
unRegister.set( elemIDs ) unRegister.set( elems )
self.editor.SplitVolumesIntoTetra(elemIDs, method) self.editor.SplitVolumesIntoTetra(elems, method)
## Splits hexahedra into prisms
# @param elems either a list of elements or a mesh or a group or a submesh or a filter
# @param startHexPoint a point used to find a hexahedron for which @a facetNormal
# gives a normal vector defining facets to split into triangles.
# @a startHexPoint can be either a triple of coordinates or a vertex.
# @param facetNormal a normal to a facet to split into triangles of a
# hexahedron found by @a startHexPoint.
# @a facetNormal can be either a triple of coordinates or an edge.
# @param method flags passing splitting method: smesh.Hex_2Prisms, smesh.Hex_4Prisms.
# smesh.Hex_2Prisms - to split the hexahedron into 2 prisms, etc.
# @param allDomains if @c False, only hexahedra adjacent to one closest
# to @a startHexPoint are split, else @a startHexPoint
# is used to find the facet to split in all domains present in @a elems.
# @ingroup l2_modif_cutquadr
def SplitHexahedraIntoPrisms(self, elems, startHexPoint, facetNormal,
method=smeshBuilder.Hex_2Prisms, allDomains=False ):
# IDSource
unRegister = genObjUnRegister()
if isinstance( elems, Mesh ):
elems = elems.GetMesh()
if ( isinstance( elems, list )):
elems = self.editor.MakeIDSource(elems, SMESH.VOLUME)
unRegister.set( elems )
pass
# axis
if isinstance( startHexPoint, geomBuilder.GEOM._objref_GEOM_Object):
startHexPoint = self.geompyD.PointCoordinates( startHexPoint )
if isinstance( facetNormal, geomBuilder.GEOM._objref_GEOM_Object):
facetNormal = self.geompyD.VectorCoordinates( facetNormal )
axis = SMESH.AxisStruct( startHexPoint[0], startHexPoint[1], startHexPoint[2],
facetNormal[0], facetNormal[1], facetNormal[2])
self.mesh.SetParameters( axis.parameters )
self.editor.SplitHexahedraIntoPrisms(elems, method, axis, allDomains)
## Splits quadrangle faces near triangular facets of volumes ## Splits quadrangle faces near triangular facets of volumes
# #
@ -3187,8 +3233,8 @@ class Mesh:
# Note that nodes built on edges and boundary nodes are always fixed. # Note that nodes built on edges and boundary nodes are always fixed.
# @param MaxNbOfIterations the maximum number of iterations # @param MaxNbOfIterations the maximum number of iterations
# @param MaxAspectRatio varies in range [1.0, inf] # @param MaxAspectRatio varies in range [1.0, inf]
# @param Method is either Laplacian (SMESH.SMESH_MeshEditor.LAPLACIAN_SMOOTH) # @param Method is either Laplacian (smesh.LAPLACIAN_SMOOTH)
# or Centroidal (SMESH.SMESH_MeshEditor.CENTROIDAL_SMOOTH) # or Centroidal (smesh.CENTROIDAL_SMOOTH)
# @return TRUE in case of success, FALSE otherwise. # @return TRUE in case of success, FALSE otherwise.
# @ingroup l2_modif_smooth # @ingroup l2_modif_smooth
def Smooth(self, IDsOfElements, IDsOfFixedNodes, def Smooth(self, IDsOfElements, IDsOfFixedNodes,
@ -3206,8 +3252,8 @@ class Mesh:
# Note that nodes built on edges and boundary nodes are always fixed. # Note that nodes built on edges and boundary nodes are always fixed.
# @param MaxNbOfIterations the maximum number of iterations # @param MaxNbOfIterations the maximum number of iterations
# @param MaxAspectRatio varies in range [1.0, inf] # @param MaxAspectRatio varies in range [1.0, inf]
# @param Method is either Laplacian (SMESH.SMESH_MeshEditor.LAPLACIAN_SMOOTH) # @param Method is either Laplacian (smesh.LAPLACIAN_SMOOTH)
# or Centroidal (SMESH.SMESH_MeshEditor.CENTROIDAL_SMOOTH) # or Centroidal (smesh.CENTROIDAL_SMOOTH)
# @return TRUE in case of success, FALSE otherwise. # @return TRUE in case of success, FALSE otherwise.
# @ingroup l2_modif_smooth # @ingroup l2_modif_smooth
def SmoothObject(self, theObject, IDsOfFixedNodes, def SmoothObject(self, theObject, IDsOfFixedNodes,
@ -3223,8 +3269,8 @@ class Mesh:
# Note that nodes built on edges and boundary nodes are always fixed. # Note that nodes built on edges and boundary nodes are always fixed.
# @param MaxNbOfIterations the maximum number of iterations # @param MaxNbOfIterations the maximum number of iterations
# @param MaxAspectRatio varies in range [1.0, inf] # @param MaxAspectRatio varies in range [1.0, inf]
# @param Method is either Laplacian (SMESH.SMESH_MeshEditor.LAPLACIAN_SMOOTH) # @param Method is either Laplacian (smesh.LAPLACIAN_SMOOTH)
# or Centroidal (SMESH.SMESH_MeshEditor.CENTROIDAL_SMOOTH) # or Centroidal (smesh.CENTROIDAL_SMOOTH)
# @return TRUE in case of success, FALSE otherwise. # @return TRUE in case of success, FALSE otherwise.
# @ingroup l2_modif_smooth # @ingroup l2_modif_smooth
def SmoothParametric(self, IDsOfElements, IDsOfFixedNodes, def SmoothParametric(self, IDsOfElements, IDsOfFixedNodes,
@ -3242,8 +3288,8 @@ class Mesh:
# Note that nodes built on edges and boundary nodes are always fixed. # Note that nodes built on edges and boundary nodes are always fixed.
# @param MaxNbOfIterations the maximum number of iterations # @param MaxNbOfIterations the maximum number of iterations
# @param MaxAspectRatio varies in range [1.0, inf] # @param MaxAspectRatio varies in range [1.0, inf]
# @param Method is either Laplacian (SMESH.SMESH_MeshEditor.LAPLACIAN_SMOOTH) # @param Method is either Laplacian (smesh.LAPLACIAN_SMOOTH)
# or Centroidal (SMESH.SMESH_MeshEditor.CENTROIDAL_SMOOTH) # or Centroidal (smesh.CENTROIDAL_SMOOTH)
# @return TRUE in case of success, FALSE otherwise. # @return TRUE in case of success, FALSE otherwise.
# @ingroup l2_modif_smooth # @ingroup l2_modif_smooth
def SmoothParametricObject(self, theObject, IDsOfFixedNodes, def SmoothParametricObject(self, theObject, IDsOfFixedNodes,