of the selected elements.</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 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
them by adjusting the locations of element corners.</li>
<li>Create an \subpage extrusion_page "extrusion" along a vector.</li>
/*!
-\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.
-2D mesh is modified accordingly.
+\n This operation allows to split either any volumic elements into
+tetrahedra or hexahedra into prisms. 2D mesh is modified accordingly.
<em>To split volumes:</em>
<ol>
-<li>Display a mesh or a submesh in the 3D viewer.</li>
-<li>In the \b Modification menu select the <b>Split into Tetrahedra</b> item or
-click <em>"Split into Tetrahedra"</em> button in the toolbar.
+<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 Volumes</b> item or
+click <em>"Split Volumes"</em> button in the toolbar.
\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:
\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>
-<li>The main list contains the list of volumes. You can click on
-a volume in the 3D viewer and it will be highlighted (lock Shift
-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
-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
-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
-non-conform.</li>
+<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
+ 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
+ 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
+ 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 non-conform.</li>
<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>
-<li>\b Split hexahedron
+<li><b> Split hexahedron </b> group allows to specify a method of
+ splitting hexahedra.
<ul>
-<li><b>Into 5 tetrahedra</b>, <b>Into 6 tetrahedra</b> and <b>Into 24 tetrahedra</b> allows to
-specify the number of tetrahedra a hexahedron will be split into. If the specified method does
-not allow to get a conform mesh, a generic solution is applied: an additional node
-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>
-</ul>
-
+<li><b>Into N tetrahedra/prisms</b> allows to specify the number of
+ tetrahedra or prisms a hexahedron will be split into. If the
+ specified method does not allow to get a conform mesh, a generic
+ solution is applied: an additional node 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>
+<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>
+</ul>
-<li><b>Select from</b> a set of fields allows to choose a submesh or an
-existing group whose elements will be automatically added to the
-list.</li>
+<li><b>Select from</b> a set of fields allows to choose a sub-mesh or an
+ existing group whose elements will be added to the list as you ckick
+ \b Add button.</li>
</ul>
<li>Click the \b Apply or <b>Apply and Close</b> button to confirm the operation.</li>
void SplitVolumesIntoTetra(in SMESH_IDSource elems, in short methodFlags)
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 };
int SMDS_VtkVolume::NbCornerNodes() const
{
vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid();
- int nbN = grid->GetCell(myVtkID)->GetNumberOfPoints();
vtkIdType aVtkType = grid->GetCellType(myVtkID);
switch (aVtkType)
{
case VTK_TRIQUADRATIC_HEXAHEDRON: return 8;
default:;
}
- return nbN;
+ return grid->GetCell(myVtkID)->GetNumberOfPoints();
}
SMDSAbs_EntityType SMDS_VtkVolume::GetEntityType() const
const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
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
{
int _n1, _n2, _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 hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
+ bool hasAdjacentVol( const SMDS_MeshElement* elem,
+ const SMDSAbs_GeometryType geom = SMDSGeom_TETRA) const;
};
struct TSplitMethod
{
- int _nbTetra;
+ int _nbSplits;
+ int _nbCorners;
const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
bool _baryNode; //!< additional node is to be created at cell barycenter
bool _ownConn; //!< to delete _connectivity in destructor
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)
- : _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; }
bool hasFacet( const TTriangleFacet& facet ) const
{
- const int* tetConn = _connectivity;
- for ( ; tetConn[0] >= 0; tetConn += 4 )
- if (( facet.contains( tetConn[0] ) +
- facet.contains( tetConn[1] ) +
- facet.contains( tetConn[2] ) +
- facet.contains( tetConn[3] )) == 3 )
- return true;
+ if ( _nbCorners == 4 )
+ {
+ const int* tetConn = _connectivity;
+ for ( ; tetConn[0] >= 0; tetConn += 4 )
+ if (( facet.contains( tetConn[0] ) +
+ facet.contains( tetConn[1] ) +
+ 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;
}
};
//=======================================================================
/*!
- * \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;
{
TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
- if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
- else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
+ if ( t012.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t012 );
+ else if ( t123.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t123 );
}
else
{
TTriangleFacet t023( nInd[ iQ * ( iCom )],
nInd[ iQ * ( (iCom+2)%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( t023 );
default:
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,
// all found splits must be among facets of tetras described by this method
method = TSplitMethod( nbTet, connVariants[variant] );
- if ( hasAdjacentSplits && method._nbTetra > 0 )
+ if ( hasAdjacentSplits && method._nbSplits > 0 )
{
bool facetCreated = true;
for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
}
}
}
- if ( method._nbTetra < 1 )
+ if ( method._nbSplits < 1 )
{
// No standard method is applicable, use a generic solution:
// each facet of a volume is split into triangles and
connectivity[ connSize++ ] = baryCenInd;
}
}
- method._nbTetra += nbTet;
+ method._nbSplits += nbTet;
} // loop on volume faces
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
*/
//================================================================================
- 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
const SMDS_MeshNode* n1 = elem->GetNode(_n1);
while ( volIt1->more() )
{
const SMDS_MeshElement* v = volIt1->next();
- SMDSAbs_EntityType type = v->GetEntityType();
- if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
+ if ( v->GetGeomType() != geom )
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
const int ind2 = v->GetNodeIndex( n2 );
- if ( ind2 < 0 || 3 < ind2 )
+ if ( ind2 < 0 || lastCornerInd < ind2 )
continue;
const int ind3 = v->GetNodeIndex( n3 );
- if ( ind3 < 0 || 3 < ind3 )
+ if ( ind3 < 0 || lastCornerInd < ind3 )
continue;
return true;
}
} // namespace
//=======================================================================
-//function : SplitVolumesIntoTetra
-//purpose : Split volume elements into tetrahedra.
+//function : SplitVolumes
+//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,
- const int theMethodFlags)
+void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems,
+ const int theMethodFlags)
{
// std-like iterator on coordinates of nodes of mesh element
typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
NXyzIterator xyzEnd;
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* fSubMesh = 0;//subMesh;
map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
double bc[3];
- TIDSortedElemSet::const_iterator elem = theElems.begin();
- for ( ; elem != theElems.end(); ++elem )
+ TFacetOfElem::const_iterator elem2facet = theElems.begin();
+ 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;
- SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
+ const SMDSAbs_EntityType geomType = elem->GetEntityType();
if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
continue;
- if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
+ if ( !volTool.Set( elem, /*ignoreCentralNodes=*/false )) continue; // strange...
- TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
- if ( splitMethod._nbTetra < 1 ) continue;
+ TSplitMethod splitMethod = ( facetToSplit < 0 ?
+ getTetraSplitMethod( volTool, theMethodFlags ) :
+ getPrismSplitMethod( volTool, theMethodFlags, facetToSplit ));
+ if ( splitMethod._nbSplits < 1 ) continue;
// 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
subMesh = GetMeshDS()->MeshElements( shapeID );
}
int iQ;
- if ( (*elem)->IsQuadratic() )
+ if ( elem->IsQuadratic() )
{
iQ = 2;
// add quadratic links to the helper
iQ = 1;
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 );
if ( splitMethod._baryNode )
{
}
}
- // make tetras
- vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
- const int* tetConn = splitMethod._connectivity;
- for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
- newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
- nodes[ tetConn[1] ],
- nodes[ tetConn[2] ],
- nodes[ tetConn[3] ]));
+ // make new volumes
+ vector<const SMDS_MeshElement* > splitVols( splitMethod._nbSplits ); // splits of a volume
+ const int* volConn = splitMethod._connectivity;
+ if ( splitMethod._nbCorners == 4 ) // tetra
+ 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] ]));
+ 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
map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
if ( iF_n != splitMethod._faceBaryNode.end() )
{
+ const SMDS_MeshNode *baryNode = iF_n->second;
for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
{
const SMDS_MeshNode* n1 = fNodes[iN];
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 ))
swap( n2, n3 );
triangles.push_back( helper.AddFace( n1,n2,n3 ));
-
- if ( fSubMesh && n3->getshapeId() < 1 )
- fSubMesh->AddNode( n3 );
+ }
+ if ( fSubMesh ) // update position of the bary node on geometry
+ {
+ 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
}
}
list< TTriangleFacet >::iterator facet = facets.begin();
+ if ( facet == facets.end() )
+ break;
for ( ; facet != facets.end(); ++facet )
{
if ( !volTool.IsFaceExternal( iF ))
}
ReplaceElemInGroups( face, triangles, GetMeshDS() );
GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
- }
+ } // while a face based on facet nodes exists
} // 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 )
{
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
//purpose : add elemToAdd to the groups the elemInGroups belongs to
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 };
else if ( theCommandID == 410 )
aDlg = new SMESHGUI_UnionOfTrianglesDlg(this);
else if ( theCommandID == 419 )
- aDlg = new SMESHGUI_CuttingIntoTetraDlg(this);
+ aDlg = new SMESHGUI_SplitVolumesDlg(this);
else
aDlg = new SMESHGUI_CuttingOfQuadsDlg(this);
#include "SMESHGUI_SpinBox.h"
#include "SMESHGUI_MeshEditPreview.h"
-#include <SMESH_Actor.h>
-#include <SMESH_TypeFilter.hxx>
-#include <SMDS_Mesh.hxx>
+#include "SMDS_Mesh.hxx"
+#include "SMDS_MeshNode.hxx"
+#include "SMDS_VolumeTool.hxx"
+#include "SMESH_Actor.h"
+#include "SMESH_MeshAlgos.hxx"
+#include "SMESH_TypeFilter.hxx"
// SALOME GUI includes
#include <SUIT_Desktop.h>
#include <VTKViewer_CellLocationsArray.h>
// OCCT includes
-#include <TColStd_IndexedMapOfInteger.hxx>
+#include <Bnd_B3d.hxx>
#include <TColStd_DataMapOfIntegerInteger.hxx>
+#include <TColStd_IndexedMapOfInteger.hxx>
#include <TColStd_MapIteratorOfMapOfInteger.hxx>
+#include <gp_Ax1.hxx>
// VTK includes
#include <vtkIdList.h>
// Purpose : Constructor
//=======================================================================
SMESHGUI_MultiEditDlg
-::SMESHGUI_MultiEditDlg(SMESHGUI* theModule,
- const int theMode,
- const bool the3d2d):
+::SMESHGUI_MultiEditDlg(SMESHGUI* theModule,
+ const int theMode,
+ const bool the3d2d,
+ bool theDoInit):
SMESHGUI_PreviewDlg(theModule),
mySelector(SMESH::GetViewWindow(theModule)->GetSelector()),
mySelectionMgr(SMESH::GetSelectionMgr(theModule)),
aDlgLay->addWidget(aMainFrame);
aDlgLay->addWidget(aBtnFrame);
- Init();
+ if ( theDoInit )
+ Init();
}
//=======================================================================
QRadioButton* aFaceRb = new QRadioButton(tr("SMESH_FACE"), aEntityTypeGrp);
QRadioButton* aVolumeRb = new QRadioButton(tr("SMESH_VOLUME"), aEntityTypeGrp);
+
aEntityLayout->addWidget(aFaceRb);
aEntityLayout->addWidget(aVolumeRb);
myComboBoxFunctor->addItem(tr("ASPECTRATIO_ELEMENTS"));
myComboBoxFunctor->addItem(tr("MINIMUMANGLE_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);
aCriterionLayout->addWidget(myChoiceWidget);
bool SMESHGUI_MultiEditDlg::isValid (const bool /*theMess*/)
{
return (!myMesh->_is_nil() &&
- (myListBox->count() > 0 || (myToAllChk->isChecked()/* && myActor*/)));
+ (myListBox->count() > 0 || (myToAllChk->isChecked() && nbElemsInMesh() > 0)));
}
//=======================================================================
return theEditor->ReorientObject( obj );
}
+int SMESHGUI_ChangeOrientationDlg::nbElemsInMesh()
+{
+ return ( myFilterType = SMESH::FaceFilter ) ? myMesh->NbFaces() : myMesh->NbVolumes();
+}
+
/*!
* Class : SMESHGUI_UnionOfTrianglesDlg
* Description : Construction of quadrangles by automatic association of triangles
ok = theEditor->TriToQuadObject(obj, aCriterion, aMaxAngle);
return ok;
}
+
+int SMESHGUI_UnionOfTrianglesDlg::nbElemsInMesh()
+{
+ return myMesh->NbTriangles();
+}
void SMESHGUI_UnionOfTrianglesDlg::onDisplaySimulation( bool toDisplayPreview )
{
if ( myPreviewCheckBox->isChecked() && toDisplayPreview ) {
if ( isValid( true ) ) {
try{
- SUIT_OverrideCursor aWaitCursor;
- // get Ids of elements
- SMESH::SMESH_IDSource_var obj;
- SMESH::long_array_var anElemIds = getIds( obj );
+ SUIT_OverrideCursor aWaitCursor;
+ // get Ids of elements
+ SMESH::SMESH_IDSource_var obj;
+ SMESH::long_array_var anElemIds = getIds( obj );
- SMESH::NumericalFunctor_var aCriterion = getNumericalFunctor();
- SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditPreviewer();
+ SMESH::NumericalFunctor_var aCriterion = getNumericalFunctor();
+ 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 ) )
- aMeshEditor->TriToQuad( anElemIds.inout(), aCriterion, aMaxAngle );
- else
- aMeshEditor->TriToQuadObject( obj, aCriterion, aMaxAngle );
+ if ( CORBA::is_nil( obj ) )
+ aMeshEditor->TriToQuad( anElemIds.inout(), aCriterion, aMaxAngle );
+ else
+ aMeshEditor->TriToQuadObject( obj, aCriterion, aMaxAngle );
- SMESH::MeshPreviewStruct_var aMeshPreviewStruct = aMeshEditor->GetPreviewData();
+ SMESH::MeshPreviewStruct_var aMeshPreviewStruct = aMeshEditor->GetPreviewData();
- vtkProperty* aProp = vtkProperty::New();
- aProp->SetRepresentationToWireframe();
- aProp->SetColor( 250, 0, 250 );
- aProp->SetLineWidth( SMESH::GetFloat( "SMESH:element_width", 1 ) + 3 );
- mySimulation->GetActor()->SetProperty( aProp );
- aProp->Delete();
+ vtkProperty* aProp = vtkProperty::New();
+ aProp->SetRepresentationToWireframe();
+ aProp->SetColor( 250, 0, 250 );
+ aProp->SetLineWidth( SMESH::GetFloat( "SMESH:element_width", 1 ) + 3 );
+ mySimulation->GetActor()->SetProperty( aProp );
+ aProp->Delete();
- mySimulation->SetData( aMeshPreviewStruct._retn() );
+ mySimulation->SetData( aMeshPreviewStruct._retn() );
} catch ( ... ) {
- hidePreview();
+ hidePreview();
}
} else {
hidePreview();
return hasObj ? theEditor->QuadToTriObject(obj, aCrit) : theEditor->QuadToTri(theIds, aCrit);
}
+int SMESHGUI_CuttingOfQuadsDlg::nbElemsInMesh()
+{
+ return myMesh->NbQuadrangles();
+}
+
+
void SMESHGUI_CuttingOfQuadsDlg::onCriterionRB()
{
if (myGroupChoice->checkedId() == 2) // Use numeric functor
}
/*!
- * Class : SMESHGUI_CuttingIntoTetraDlg
- * Description : Modification of orientation of faces
+ * Class : SMESHGUI_SplitVolumesDlg
+ * Description : Spliter of volumes into tetrahedra or prisms
*/
-SMESHGUI_CuttingIntoTetraDlg::SMESHGUI_CuttingIntoTetraDlg(SMESHGUI* theModule)
- : SMESHGUI_MultiEditDlg(theModule, SMESH::VolumeFilter, false)
+SMESHGUI_SplitVolumesDlg::SMESHGUI_SplitVolumesDlg(SMESHGUI* theModule)
+ : SMESHGUI_MultiEditDlg(theModule, SMESH::VolumeFilter, /*the3d2d=*/true, /*doInit=*/false)
{
setWindowTitle(tr("CAPTION"));
myHelpFileName = "split_to_tetra_page.html";
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
bool hasHexa = true;//myMesh->_is_nil() ? false : myMesh->NbHexas();
-
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->show();
myComboBoxFunctor->hide();
myChoiceWidget->show();
}
- setSelectionMode();
- updateButtons();
+
+ on3d2dChanged( 0 );
+ Init();
}
-SMESHGUI_CuttingIntoTetraDlg::~SMESHGUI_CuttingIntoTetraDlg()
+SMESHGUI_SplitVolumesDlg::~SMESHGUI_SplitVolumesDlg()
{
}
-bool SMESHGUI_CuttingIntoTetraDlg::process (SMESH::SMESH_MeshEditor_ptr theEditor,
- const SMESH::long_array& theIds,
- SMESH::SMESH_IDSource_ptr theObj)
+bool SMESHGUI_SplitVolumesDlg::process (SMESH::SMESH_MeshEditor_ptr theEditor,
+ const SMESH::long_array& theIds,
+ SMESH::SMESH_IDSource_ptr theObj)
{
SMESH::SMESH_IDSource_wrap obj = theObj;
if ( CORBA::is_nil( obj ))
- obj = theEditor->MakeIDSource( theIds, myEntityType ? SMESH::VOLUME : SMESH::FACE );
+ obj = theEditor->MakeIDSource( theIds, SMESH::VOLUME );
else
obj->Register();
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 ) {
SalomeApp_Tools::QtCatchCorbaException( S_ex );
}
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();
+}
Q_OBJECT
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();
void Init();
void onHelp();
void onDeactivate();
- void onSelectionDone();
+ virtual void onSelectionDone();
void onFilterBtn();
void onAddBtn();
void onGroupChk();
virtual void onToAllChk();
void onFilterAccepted();
- void on3d2dChanged(int);
+ virtual void on3d2dChanged(int);
SMESH::NumericalFunctor_ptr getNumericalFunctor();
virtual bool isValid( const bool );
SMESH::long_array_var getIds(SMESH::SMESH_IDSource_var& obj);
void updateButtons();
- void setSelectionMode();
+ virtual void setSelectionMode();
virtual bool isIdValid( const int ) const;
virtual bool process( SMESH::SMESH_MeshEditor_ptr,
const SMESH::long_array& ,
SMESH::SMESH_IDSource_ptr obj) = 0;
+ virtual int nbElemsInMesh() = 0;
int entityType();
protected:
virtual bool process( SMESH::SMESH_MeshEditor_ptr,
const SMESH::long_array& ,
SMESH::SMESH_IDSource_ptr obj);
+ virtual int nbElemsInMesh();
};
/*!
virtual bool process( SMESH::SMESH_MeshEditor_ptr,
const SMESH::long_array&,
SMESH::SMESH_IDSource_ptr obj );
+ virtual int nbElemsInMesh();
protected slots:
virtual void onDisplaySimulation( bool );
virtual bool process( SMESH::SMESH_MeshEditor_ptr,
const SMESH::long_array& ,
SMESH::SMESH_IDSource_ptr obj);
+ virtual int nbElemsInMesh();
protected slots:
virtual void reject();
};
/*!
- * Class : SMESHGUI_CuttingIntoTetraDlg
+ * Class : SMESHGUI_SplitVolumesDlg
* Description : Split all volumes into tetrahedrons
*/
-class SMESHGUI_CuttingIntoTetraDlg : public SMESHGUI_MultiEditDlg
+class SMESHGUI_SplitVolumesDlg : public SMESHGUI_MultiEditDlg
{
Q_OBJECT
public:
- SMESHGUI_CuttingIntoTetraDlg( SMESHGUI* );
- virtual ~SMESHGUI_CuttingIntoTetraDlg();
+ SMESHGUI_SplitVolumesDlg( SMESHGUI* );
+ virtual ~SMESHGUI_SplitVolumesDlg();
+
+protected slots:
+
+ virtual void on3d2dChanged(int);
+ virtual void onSelectionDone();
+
+ void onFacetSelection(bool);
+ void onSetDir();
+ void updateNormalPreview(const QString& s="");
protected:
+
virtual bool process( SMESH::SMESH_MeshEditor_ptr,
const SMESH::long_array&,
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
</message>
<message>
<source>MEN_SPLIT_TO_TETRA</source>
- <translation>Split into Tetrahedra</translation>
+ <translation>Split Volumes</translation>
</message>
<message>
<source>TOP_SPLIT_TO_TETRA</source>
- <translation>Split into Tetrahedra</translation>
+ <translation>Split Volumes</translation>
</message>
<message>
<source>STB_SPLIT_TO_TETRA</source>
- <translation>Split into Tetrahedra</translation>
+ <translation>Split Volumes</translation>
</message>
<message>
<source>MESHERS_FILE_CANT_OPEN</source>
</message>
</context>
<context>
- <name>SMESHGUI_CuttingIntoTetraDlg</name>
+ <name>SMESHGUI_SplitVolumesDlg</name>
<message>
<source>CAPTION</source>
- <translation>Splitting volumes into tetrahedra</translation>
+ <translation>Splitting volumes</translation>
</message>
<message>
<source>SPLIT_METHOD</source>
<source>SPLIT_HEX_TO_24_TETRA</source>
<translation>Into 24 tetrahedra</translation>
</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>
<name>SMESHGUI_PrecisionDlg</name>
{
SMESH_TRY;
initData();
-
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()
TPythonDump() << this << ".SplitVolumesIntoTetra( "
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
//purpose :
void SplitVolumesIntoTetra(SMESH::SMESH_IDSource_ptr elems,
CORBA::Short methodFlags)
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,
const SMESH::long_array & IDsOfFixedNodes,
## @defgroup l2_modif_invdiag Diagonal inversion of elements
## @defgroup l2_modif_unitetri Uniting triangles
## @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_extrurev Extrusion and Revolution
## @defgroup l2_modif_patterns Pattern mapping
[TopAbs_IN, TopAbs_OUT, TopAbs_ON, TopAbs_UNKNOWN] = range(4)
# 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):
global engine
## Creates a filter from criteria
# @param criteria a list of criteria
+ # @param binOp binary operator used when binary operator of criteria is undefined
# @return SMESH_Filter
#
# <a href="../tui_filters_page.html#tui_filters">Example of Filters usage</a>
# @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()
aFilter = aFilterMgr.CreateFilter()
aFilter.SetCriteria(criteria)
def GetElementGeomType(self, 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
# @param Shape a geom object(sub-shape) IOR
# Shape must be the sub-shape of a ShapeToMesh()
return self.editor.BestSplit(IDOfQuad, self.smeshpyD.GetFunctor(theCriterion))
## Splits volumic elements into tetrahedrons
- # @param elemIDs either list of elements or mesh or group or submesh
- # @param method flags passing splitting method: Hex_5Tet, Hex_6Tet, Hex_24Tet
- # Hex_5Tet - split the hexahedron into 5 tetrahedrons, etc
+ # @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:
+ # smesh.Hex_5Tet, smesh.Hex_6Tet, smesh.Hex_24Tet.
+ # smesh.Hex_5Tet - to split the hexahedron into 5 tetrahedrons, etc.
+ # @ingroup l2_modif_cutquadr
+ def SplitVolumesIntoTetra(self, elems, method=smeshBuilder.Hex_5Tet ):
+ unRegister = genObjUnRegister()
+ if isinstance( elems, Mesh ):
+ elems = elems.GetMesh()
+ if ( isinstance( elems, list )):
+ elems = self.editor.MakeIDSource(elems, SMESH.VOLUME)
+ unRegister.set( elems )
+ 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 SplitVolumesIntoTetra(self, elemIDs, method=smeshBuilder.Hex_5Tet ):
+ def SplitHexahedraIntoPrisms(self, elems, startHexPoint, facetNormal,
+ method=smeshBuilder.Hex_2Prisms, allDomains=False ):
+ # IDSource
unRegister = genObjUnRegister()
- if isinstance( elemIDs, Mesh ):
- elemIDs = elemIDs.GetMesh()
- if ( isinstance( elemIDs, list )):
- elemIDs = self.editor.MakeIDSource(elemIDs, SMESH.VOLUME)
- unRegister.set( elemIDs )
- self.editor.SplitVolumesIntoTetra(elemIDs, method)
+ 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
#
# Note that nodes built on edges and boundary nodes are always fixed.
# @param MaxNbOfIterations the maximum number of iterations
# @param MaxAspectRatio varies in range [1.0, inf]
- # @param Method is either Laplacian (SMESH.SMESH_MeshEditor.LAPLACIAN_SMOOTH)
- # or Centroidal (SMESH.SMESH_MeshEditor.CENTROIDAL_SMOOTH)
+ # @param Method is either Laplacian (smesh.LAPLACIAN_SMOOTH)
+ # or Centroidal (smesh.CENTROIDAL_SMOOTH)
# @return TRUE in case of success, FALSE otherwise.
# @ingroup l2_modif_smooth
def Smooth(self, IDsOfElements, IDsOfFixedNodes,
# Note that nodes built on edges and boundary nodes are always fixed.
# @param MaxNbOfIterations the maximum number of iterations
# @param MaxAspectRatio varies in range [1.0, inf]
- # @param Method is either Laplacian (SMESH.SMESH_MeshEditor.LAPLACIAN_SMOOTH)
- # or Centroidal (SMESH.SMESH_MeshEditor.CENTROIDAL_SMOOTH)
+ # @param Method is either Laplacian (smesh.LAPLACIAN_SMOOTH)
+ # or Centroidal (smesh.CENTROIDAL_SMOOTH)
# @return TRUE in case of success, FALSE otherwise.
# @ingroup l2_modif_smooth
def SmoothObject(self, theObject, IDsOfFixedNodes,
# Note that nodes built on edges and boundary nodes are always fixed.
# @param MaxNbOfIterations the maximum number of iterations
# @param MaxAspectRatio varies in range [1.0, inf]
- # @param Method is either Laplacian (SMESH.SMESH_MeshEditor.LAPLACIAN_SMOOTH)
- # or Centroidal (SMESH.SMESH_MeshEditor.CENTROIDAL_SMOOTH)
+ # @param Method is either Laplacian (smesh.LAPLACIAN_SMOOTH)
+ # or Centroidal (smesh.CENTROIDAL_SMOOTH)
# @return TRUE in case of success, FALSE otherwise.
# @ingroup l2_modif_smooth
def SmoothParametric(self, IDsOfElements, IDsOfFixedNodes,
# Note that nodes built on edges and boundary nodes are always fixed.
# @param MaxNbOfIterations the maximum number of iterations
# @param MaxAspectRatio varies in range [1.0, inf]
- # @param Method is either Laplacian (SMESH.SMESH_MeshEditor.LAPLACIAN_SMOOTH)
- # or Centroidal (SMESH.SMESH_MeshEditor.CENTROIDAL_SMOOTH)
+ # @param Method is either Laplacian (smesh.LAPLACIAN_SMOOTH)
+ # or Centroidal (smesh.CENTROIDAL_SMOOTH)
# @return TRUE in case of success, FALSE otherwise.
# @ingroup l2_modif_smooth
def SmoothParametricObject(self, theObject, IDsOfFixedNodes,