Salome HOME
22316: EDF 2719 SMESH: Split hexas into prisms
authoreap <eap@opencascade.com>
Mon, 20 Jan 2014 10:31:23 +0000 (10:31 +0000)
committereap <eap@opencascade.com>
Mon, 20 Jan 2014 10:31:23 +0000 (10:31 +0000)
15 files changed:
doc/salome/gui/SMESH/images/split_into_prisms.png [new file with mode: 0644]
doc/salome/gui/SMESH/images/split_into_tetra.png
doc/salome/gui/SMESH/input/modifying_meshes.doc
doc/salome/gui/SMESH/input/split_to_tetra.doc
idl/SMESH_MeshEditor.idl
src/SMDS/SMDS_VtkVolume.cxx
src/SMESH/SMESH_MeshEditor.cxx
src/SMESH/SMESH_MeshEditor.hxx
src/SMESHGUI/SMESHGUI.cxx
src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx
src/SMESHGUI/SMESHGUI_MultiEditDlg.h
src/SMESHGUI/SMESH_msg_en.ts
src/SMESH_I/SMESH_MeshEditor_i.cxx
src/SMESH_I/SMESH_MeshEditor_i.hxx
src/SMESH_SWIG/smeshBuilder.py

diff --git a/doc/salome/gui/SMESH/images/split_into_prisms.png b/doc/salome/gui/SMESH/images/split_into_prisms.png
new file mode 100644 (file)
index 0000000..6b9f77a
Binary files /dev/null and b/doc/salome/gui/SMESH/images/split_into_prisms.png differ
index fce071e7df37c5914ca74ee34026bbf1fa79c973..a54f4452972e6e84792a95d1535879a537d08475 100644 (file)
Binary files a/doc/salome/gui/SMESH/images/split_into_tetra.png and b/doc/salome/gui/SMESH/images/split_into_tetra.png differ
index b7b7e2e646050fdd1ab262c3b5f9be5701237586..d32e56a488901ca2d6b81088814edc2fdc9c5f59 100644 (file)
@@ -39,7 +39,7 @@ with consequent transformation of all adjacent elements and edges.</li>
  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>
index 325c30c116209cfc4187a1ab5f5aa7c4d0e60e7f..eb7fe0f26805f7dbf3c42157519ef0e091066cd0 100644 (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. 
-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>
index 43d7eac35bb09a0aded02422a33f99a6c76ede1a..13107425dabe993c33c795da970b5c62cf766629 100644 (file)
@@ -323,6 +323,25 @@ module SMESH
     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 };
 
index 7acdbf37c110daff9dae1c5bdc6632384225e5b2..e65875f8b3c12bc515a001202bf46c7372d707aa 100644 (file)
@@ -557,7 +557,6 @@ bool SMDS_VtkVolume::IsMediumNode(const SMDS_MeshNode* node) const
 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)
   {
@@ -568,7 +567,7 @@ int SMDS_VtkVolume::NbCornerNodes() const
   case VTK_TRIQUADRATIC_HEXAHEDRON: return 8;
   default:;
   }
-  return nbN;
+  return grid->GetCell(myVtkID)->GetNumberOfPoints();
 }
 
 SMDSAbs_EntityType SMDS_VtkVolume::GetEntityType() const
index 842b177507e10c3f190e4a1d626a26ca6c4a1bff..8e444dec8c449f231bc70ff21ea89bfb24337f2d 100644 (file)
@@ -1603,44 +1603,110 @@ namespace
   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;
 
@@ -1665,8 +1731,8 @@ namespace
       {
         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
       {
@@ -1679,7 +1745,7 @@ namespace
           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 );
@@ -1719,12 +1785,12 @@ namespace
       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 )
@@ -1738,7 +1804,7 @@ namespace
         }
       }
     }
-    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
@@ -1832,7 +1898,7 @@ namespace
             connectivity[ connSize++ ] = baryCenInd;
           }
         }
-        method._nbTetra += nbTet;
+        method._nbSplits += nbTet;
 
       } // loop on volume faces
 
@@ -1842,13 +1908,132 @@ namespace
 
     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);
@@ -1858,16 +2043,16 @@ namespace
     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;
     }
@@ -1900,19 +2085,23 @@ namespace
 } // 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;
@@ -1923,29 +2112,33 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
   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
@@ -1963,7 +2156,8 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
       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 )
     {
@@ -1991,16 +2185,25 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
       }
     }
 
-    // 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
 
@@ -2029,17 +2232,37 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
         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
@@ -2069,6 +2292,8 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
             }
           }
           list< TTriangleFacet >::iterator facet = facets.begin();
+          if ( facet == facets.end() )
+            break;
           for ( ; facet != facets.end(); ++facet )
           {
             if ( !volTool.IsFaceExternal( iF ))
@@ -2087,11 +2312,11 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
         }
         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 )
     {
@@ -2106,6 +2331,198 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
   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
index 870660a8aa4adbef75f0deafbe441e65d9344e3d..8380cc900323d7674d40cb3631fbf32ecb7862a8 100644 (file)
@@ -169,11 +169,32 @@ public:
                  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 };
index 6fb58cea1ddc998627ad5579751107b9cb734c47..1dca53b610cd8301da79b4cdb207d874c476244b 100644 (file)
@@ -2668,7 +2668,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID )
       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);
 
index d48e740f5903e8ef301126e4589cd7a20f32b9ce..a252ce333238a2c3080adcea34843c64534c507b 100755 (executable)
 #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)),
@@ -128,7 +134,8 @@ SMESHGUI_MultiEditDlg
   aDlgLay->addWidget(aMainFrame);
   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* aVolumeRb = new QRadioButton(tr("SMESH_VOLUME"), aEntityTypeGrp);
 
+
     aEntityLayout->addWidget(aFaceRb);
     aEntityLayout->addWidget(aVolumeRb);
 
@@ -226,9 +234,6 @@ QWidget* SMESHGUI_MultiEditDlg::createMainFrame (QWidget* theParent, const bool
   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);
@@ -305,7 +310,7 @@ QWidget* SMESHGUI_MultiEditDlg::createButtonFrame (QWidget* theParent)
 bool SMESHGUI_MultiEditDlg::isValid (const bool /*theMess*/)
 {
   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 );
 }
 
+int SMESHGUI_ChangeOrientationDlg::nbElemsInMesh()
+{
+  return ( myFilterType = SMESH::FaceFilter ) ? myMesh->NbFaces() : myMesh->NbVolumes();
+}
+
 /*!
  *  Class       : SMESHGUI_UnionOfTrianglesDlg
  *  Description : Construction of quadrangles by automatic association of triangles
@@ -1163,39 +1173,44 @@ bool SMESHGUI_UnionOfTrianglesDlg::process (SMESH::SMESH_MeshEditor_ptr theEdito
     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();
@@ -1279,6 +1294,12 @@ bool SMESHGUI_CuttingOfQuadsDlg::process (SMESH::SMESH_MeshEditor_ptr theEditor,
   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
@@ -1488,51 +1509,147 @@ void SMESHGUI_CuttingOfQuadsDlg::displayPreview()
 }
 
 /*!
- *  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 );
@@ -1543,3 +1660,308 @@ bool SMESHGUI_CuttingIntoTetraDlg::process (SMESH::SMESH_MeshEditor_ptr theEdito
   }
   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();
+}
index 68847772b6536db491a7644e1cd35313e74bb0af..1bd9cb5ad07a2fd59c5eb4631d097a308e96343c 100755 (executable)
@@ -70,7 +70,10 @@ class SMESHGUI_EXPORT SMESHGUI_MultiEditDlg : public SMESHGUI_PreviewDlg
   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();
@@ -87,7 +90,7 @@ protected slots:
   void                      onHelp();
 
   void                      onDeactivate();
-  void                      onSelectionDone();
+  virtual void              onSelectionDone();
 
   void                      onFilterBtn();
   void                      onAddBtn();
@@ -98,7 +101,7 @@ protected slots:
   void                      onGroupChk();
   virtual void              onToAllChk();
   void                      onFilterAccepted();
-  void                      on3d2dChanged(int);
+  virtual void              on3d2dChanged(int);
 
   SMESH::NumericalFunctor_ptr getNumericalFunctor();
 
@@ -110,11 +113,12 @@ protected:
   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:
@@ -178,6 +182,7 @@ protected:
   virtual bool process( SMESH::SMESH_MeshEditor_ptr,
                         const SMESH::long_array& ,
                         SMESH::SMESH_IDSource_ptr obj);
+  virtual int  nbElemsInMesh();
 };
 
 /*!
@@ -197,6 +202,7 @@ protected:
   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 );
@@ -221,6 +227,7 @@ protected:
   virtual bool  process( SMESH::SMESH_MeshEditor_ptr,
                          const SMESH::long_array& ,
                          SMESH::SMESH_IDSource_ptr obj);
+  virtual int   nbElemsInMesh();
 
 protected slots:
   virtual void  reject();
@@ -237,21 +244,45 @@ private:
 };
 
 /*!
- * 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
index df41ace147f67e21abb4a4ef529b461a1f3cb027..1825f17f44bd2b75e2351a1fa8d7e84daac8f9f4 100644 (file)
     </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>
@@ -6278,10 +6278,10 @@ It is impossible to read point coordinates from file</translation>
     </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>
@@ -6299,6 +6299,34 @@ It is impossible to read point coordinates from file</translation>
         <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>
index 69bf34ec12d21a49fba0617182175f699810c31c..b066d249245676a7f8f50c59e6951d837b0d04b8 100644 (file)
@@ -1999,13 +1999,15 @@ void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems,
 {
   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( "
@@ -2014,6 +2016,66 @@ void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems,
   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  :
index e74df378834285a2cc7c147dbfde1ddb327da45c..ed67dabef72cee3df67c86849a9a975ed22f65d2 100644 (file)
@@ -233,6 +233,11 @@ public:
   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,
index a5aae93d2898f2142e804323fa31d6d2b0058435..4e7c418e494ef2d46f09308338661fd1b08fecd8 100644 (file)
@@ -73,7 +73,7 @@
 ##   @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
@@ -307,7 +307,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
     [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
@@ -851,11 +851,15 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
 
     ## 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)
@@ -2284,6 +2288,12 @@ class Mesh:
     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()
@@ -3026,18 +3036,54 @@ class Mesh:
         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
     #
@@ -3187,8 +3233,8 @@ class Mesh:
     #  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,
@@ -3206,8 +3252,8 @@ class Mesh:
     #  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,
@@ -3223,8 +3269,8 @@ class Mesh:
     #  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,
@@ -3242,8 +3288,8 @@ class Mesh:
     #  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,