Salome HOME
23072: [CEA 1500] Split biquadratic elements into linear elements
authoreap <eap@opencascade.com>
Thu, 9 Jul 2015 09:41:53 +0000 (12:41 +0300)
committereap <eap@opencascade.com>
Thu, 9 Jul 2015 09:41:53 +0000 (12:41 +0300)
29 files changed:
doc/salome/examples/CMakeLists.txt
doc/salome/examples/split_biquad.py [new file with mode: 0644]
doc/salome/examples/transforming_meshes_ex01.py
doc/salome/gui/SMESH/images/split_biquad_to_linear_dlg.png [new file with mode: 0644]
doc/salome/gui/SMESH/images/split_biquad_to_linear_icon.png [new file with mode: 0644]
doc/salome/gui/SMESH/images/split_biquad_to_linear_mesh.png [new file with mode: 0644]
doc/salome/gui/SMESH/input/convert_to_from_quadratic_mesh.doc
doc/salome/gui/SMESH/input/modifying_meshes.doc
doc/salome/gui/SMESH/input/split_biquad_to_linear.doc [new file with mode: 0644]
doc/salome/gui/SMESH/input/split_to_tetra.doc
doc/salome/gui/SMESH/input/tui_modifying_meshes.doc
idl/SMESH_MeshEditor.idl
resources/CMakeLists.txt
resources/split_biquad.png [new file with mode: 0644]
src/SMESH/SMESH_MeshEditor.cxx
src/SMESH/SMESH_MeshEditor.hxx
src/SMESHGUI/CMakeLists.txt
src/SMESHGUI/SMESHGUI.cxx
src/SMESHGUI/SMESHGUI_ConvToQuadOp.cxx
src/SMESHGUI/SMESHGUI_Operations.h
src/SMESHGUI/SMESHGUI_SplitBiQuad.cxx [new file with mode: 0644]
src/SMESHGUI/SMESHGUI_SplitBiQuad.h [new file with mode: 0644]
src/SMESHGUI/SMESH_images.ts
src/SMESHGUI/SMESH_msg_en.ts
src/SMESHUtils/SMESH_MAT2d.cxx
src/SMESH_I/SMESH_MeshEditor_i.cxx
src/SMESH_I/SMESH_MeshEditor_i.hxx
src/SMESH_SWIG/smeshBuilder.py
src/StdMeshers/StdMeshers_QuadFromMedialAxis_1D2D.cxx

index 7ee8ff5..65d8e52 100644 (file)
@@ -165,6 +165,7 @@ SET(GOOD_TESTS
   transforming_meshes_ex13.py
   use_existing_faces.py
   viewing_meshes_ex02.py
+  split_biquad.py
 )
 
 SET(EXAMPLES_TESTS ${BAD_TESTS} ${GOOD_TESTS} testme.py)
diff --git a/doc/salome/examples/split_biquad.py b/doc/salome/examples/split_biquad.py
new file mode 100644 (file)
index 0000000..e53e7b0
--- /dev/null
@@ -0,0 +1,37 @@
+# Split bi-quadratic to linear
+
+import salome
+salome.salome_init()
+
+from salome.geom import geomBuilder
+geompy = geomBuilder.New(salome.myStudy)
+
+from salome.smesh import smeshBuilder
+smesh = smeshBuilder.New(salome.myStudy)
+
+# make a shape consisting of two quadranges
+OY  = geompy.MakeVectorDXDYDZ(0, 1, 0)
+OY1 = geompy.MakeTranslation( OY, 1, 0, 0 )
+OY2 = geompy.MakeTranslation( OY, 2, 0, 0 )
+q1  = geompy.MakeQuad2Edges( OY, OY1 )
+q2  = geompy.MakeQuad2Edges( OY1, OY2 )
+
+shape = geompy.Partition( [q1,q2], theName='shape' )
+ff    = geompy.SubShapeAll( shape, geompy.ShapeType["FACE"], theName="quad" )
+
+# mesh one quadrange with quadrangless and the other with triangles
+mesh = smesh.Mesh( shape )
+mesh.Segment().NumberOfSegments(1)
+mesh.Quadrangle()
+mesh.Triangle( ff[1] )
+mesh.Compute()
+
+# make group of quadrangles and extrude them into a hexahedron
+quadGroup = mesh.Group( ff[0], "quads")
+mesh.ExtrusionSweepObject2D( quadGroup, [0,0,1], 1 )
+
+# make the mesh bi-quadratic
+mesh.ConvertToQuadratic( theToBiQuad=True )
+
+# split all elements into linear ones
+mesh.SplitBiQuadraticIntoLinear()
index dc61324..93f5196 100644 (file)
@@ -1,16 +1,11 @@
 # Translation
 
 import SMESH_mechanic
-import SMESH
 
-smesh = SMESH_mechanic.smesh 
 mesh = SMESH_mechanic.mesh 
 
 # define translation vector
-point = SMESH.PointStruct(-150., -150., 0.)
-vector =SMESH.DirStruct(point)
+vector = [-150., -150., 0.]
 
-# translate a mesh
-doCopy = 1
-
-mesh.Translate([], vector, doCopy)
+# make a translated copy of all elements of the mesh
+mesh.TranslateObject(mesh, vector, Copy=True)
diff --git a/doc/salome/gui/SMESH/images/split_biquad_to_linear_dlg.png b/doc/salome/gui/SMESH/images/split_biquad_to_linear_dlg.png
new file mode 100644 (file)
index 0000000..c3df009
Binary files /dev/null and b/doc/salome/gui/SMESH/images/split_biquad_to_linear_dlg.png differ
diff --git a/doc/salome/gui/SMESH/images/split_biquad_to_linear_icon.png b/doc/salome/gui/SMESH/images/split_biquad_to_linear_icon.png
new file mode 100644 (file)
index 0000000..0b9b7a0
Binary files /dev/null and b/doc/salome/gui/SMESH/images/split_biquad_to_linear_icon.png differ
diff --git a/doc/salome/gui/SMESH/images/split_biquad_to_linear_mesh.png b/doc/salome/gui/SMESH/images/split_biquad_to_linear_mesh.png
new file mode 100644 (file)
index 0000000..4a25e8f
Binary files /dev/null and b/doc/salome/gui/SMESH/images/split_biquad_to_linear_mesh.png differ
index a8ad620..a253c05 100644 (file)
@@ -51,7 +51,7 @@ The following dialog box will appear:
 <center>Quadratic mesh</center>
 
 </li>
-<li>Click the \b Apply or \b OK button.</li>
+<li>Click the \b Apply or <b>Apply and Close</b> button.</li>
 </ol>
 
 <br><b>See Also</b> a sample TUI Script of a \ref tui_quadratic "Convert to/from quadratic" operation.
index 94002fa..3490916 100644 (file)
@@ -43,6 +43,8 @@ transformation operations, giving the possibility to:
   triangles.</li>
 <li>\subpage split_to_tetra_page "Split" volumic elements into
   tetrahedra or prisms.</li>
+<li>\subpage split_biquad_to_linear_page "Split bi-quadratic" elements
+  into linear ones without creation of additional nodes.</li>
 <li>\subpage smoothing_page "Smooth" elements, reducung distortions in
   them by adjusting the locations of nodes.</li>
 <li>Create an \subpage extrusion_page "extrusion" along a vector or by
diff --git a/doc/salome/gui/SMESH/input/split_biquad_to_linear.doc b/doc/salome/gui/SMESH/input/split_biquad_to_linear.doc
new file mode 100644 (file)
index 0000000..85002f9
--- /dev/null
@@ -0,0 +1,37 @@
+/*!
+
+\page split_biquad_to_linear_page Split bi-quadratic into linear
+
+\n This functionality allows to split bi-quadratic elements into
+linear ones without creation of additional nodes.
+
+So that
+- bi-quadratic triangle will be split into 3 linear quadrangles;
+- bi-quadratic quadrangle will be split into 4 linear quadrangles;
+- tri-quadratic hexahedron will be split into 8 linear hexahedra;
+- quadratic segments adjacent to the split bi-quadratic element will
+  be split into 2 liner segment.
+
+\image html split_biquad_to_linear_mesh.png "Mesh before and after splitting"
+
+<em>To split bi-quadratic elements into linear:</em>
+<ol>
+<li>From the \b Modification menu choose the <b>Split bi-quadratic into linear</b> item or
+click <em>"Split bi-quadratic into linear"</em> button in the toolbar.
+
+\image html split_biquad_to_linear_icon.png
+<center><em>"Split bi-quadratic into linear" button</em></center>
+
+The following dialog box shall appear:
+
+\image html split_biquad_to_linear_dlg.png
+</li>
+<li>Select a mesh, groups or sub-meshes in the Object Browser or in the
+  Viewer.</li>
+<li>Click the \b Apply or <b>Apply and Close</b> button.</li>
+</ol>
+
+<br><b>See Also</b> a sample TUI Script of a \ref tui_split_biquad "Split bi-quadratic into linear" operation.
+
+*/
index fb5c4e1..b6ee36e 100644 (file)
@@ -7,7 +7,7 @@ tetrahedra or hexahedra into prisms. 2D mesh is modified accordingly.
 
 <em>To split volumes:</em>
 <ol>
-<li>Display a mesh, a sub-mesh or a group in the 3D viewer.</li>
+<li>Select a mesh, a sub-mesh or a group.</li>
 <li>In the \b Modification menu select the <b>Split Volumes</b> item or
 click <em>"Split Volumes"</em> button in the toolbar.
 
index 7ceb5eb..1073065 100644 (file)
 <h2>Convert mesh to/from quadratic</h2>
 \tui_script{modifying_meshes_ex26.py}
 
+<br>
+\anchor tui_split_biquad
+<h2>Split bi-quadratic into linear</h2>
+\tui_script{split_biquad.py}
+
 */
index 0b43211..509e9ed 100644 (file)
@@ -360,13 +360,25 @@ module SMESH
      *         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, 
+    void SplitHexahedraIntoPrisms(in SMESH_IDSource     elems,
                                   in SMESH::PointStruct startHexPoint,
                                   in SMESH::DirStruct   facetToSplitNormal,
                                   in short              methodFlags,
                                   in boolean            allDomains)
       raises (SALOME::SALOME_Exception);
 
+    /*!
+     * \brief Split bi-quadratic elements into linear ones without creation of additional nodes.
+     *   - bi-quadratic triangle will be split into 3 linear quadrangles;
+     *   - bi-quadratic quadrangle will be split into 4 linear quadrangles;
+     *   - tri-quadratic hexahedron will be split into 8 linear hexahedra;
+     *   Quadratic elements of lower dimension  adjacent to the split bi-quadratic element
+     *   will be split in order to keep the mesh conformal.
+     *  \param elems - elements to split
+     */
+    void SplitBiQuadraticIntoLinear(in ListOfIDSources elems)
+      raises (SALOME::SALOME_Exception);
+
 
     enum Smooth_Method { LAPLACIAN_SMOOTH, CENTROIDAL_SMOOTH };
 
index 421d998..66f426f 100755 (executable)
@@ -203,6 +203,7 @@ SET(SMESH_RESOURCES_FILES
   scale.png
   scale_along_axes.png
   split_into_tetra.png
+  split_biquad.png
   mesh_duplicate_nodes.png
   mesh_duplicate_nodes_with_elem.png
   mesh_duplicate_elem_only.png
diff --git a/resources/split_biquad.png b/resources/split_biquad.png
new file mode 100644 (file)
index 0000000..0b9b7a0
Binary files /dev/null and b/resources/split_biquad.png differ
index fc945c4..54233ac 100644 (file)
@@ -2239,6 +2239,7 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems,
   // map face of volume to it's baricenrtic node
   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
   double bc[3];
+  vector<const SMDS_MeshElement* > splitVols;
 
   TFacetOfElem::const_iterator elem2facet = theElems.begin();
   for ( ; elem2facet != theElems.end(); ++elem2facet )
@@ -2314,7 +2315,7 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems,
     }
 
     // make new volumes
-    vector<const SMDS_MeshElement* > splitVols( splitMethod._nbSplits ); // splits of a volume
+    splitVols.resize( 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 )
@@ -2619,7 +2620,7 @@ void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas,
 
       startHex = curHex;
 
-      // find a facet of startHex to split 
+      // find a facet of startHex to split
 
       set<const SMDS_MeshNode*> lateralNodes;
       vTool.GetFaceNodes( lateralFacet, lateralNodes );
@@ -2649,6 +2650,188 @@ void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas,
         throw SALOME_Exception( THIS_METHOD "facet of a new startHex not found");
     }
   } //   while ( startHex )
+
+  return;
+}
+
+namespace
+{
+  //================================================================================
+  /*!
+   * \brief Selects nodes of several elements according to a given interlace
+   *  \param [in] srcNodes - nodes to select from
+   *  \param [out] tgtNodesVec - array of nodes of several elements to fill in
+   *  \param [in] interlace - indices of nodes for all elements
+   *  \param [in] nbElems - nb of elements
+   *  \param [in] nbNodes - nb of nodes in each element
+   *  \param [in] mesh - the mesh
+   *  \param [out] elemQueue - a list to push elements found by the selected nodes
+   *  \param [in] type - type of elements to look for
+   */
+  //================================================================================
+
+  void selectNodes( const vector< const SMDS_MeshNode* >& srcNodes,
+                    vector< const SMDS_MeshNode* >*       tgtNodesVec,
+                    const int*                            interlace,
+                    const int                             nbElems,
+                    const int                             nbNodes,
+                    SMESHDS_Mesh*                         mesh = 0,
+                    list< const SMDS_MeshElement* >*      elemQueue=0,
+                    SMDSAbs_ElementType                   type=SMDSAbs_All)
+  {
+    for ( int iE = 0; iE < nbElems; ++iE )
+    {
+      vector< const SMDS_MeshNode* >& elemNodes = tgtNodesVec[iE];
+      const int*                         select = & interlace[iE*nbNodes];
+      elemNodes.resize( nbNodes );
+      for ( int iN = 0; iN < nbNodes; ++iN )
+        elemNodes[iN] = srcNodes[ select[ iN ]];
+    }
+    const SMDS_MeshElement* e;
+    if ( elemQueue )
+      for ( int iE = 0; iE < nbElems; ++iE )
+        if (( e = mesh->FindElement( tgtNodesVec[iE], type, /*noMedium=*/false)))
+          elemQueue->push_back( e );
+  }
+}
+
+//=======================================================================
+/*
+ * Split bi-quadratic elements into linear ones without creation of additional nodes
+ *   - bi-quadratic triangle will be split into 3 linear quadrangles;
+ *   - bi-quadratic quadrangle will be split into 4 linear quadrangles;
+ *   - tri-quadratic hexahedron will be split into 8 linear hexahedra;
+ *   Quadratic elements of lower dimension  adjacent to the split bi-quadratic element
+ *   will be split in order to keep the mesh conformal.
+ *  \param elems - elements to split
+ */
+//=======================================================================
+
+void SMESH_MeshEditor::SplitBiQuadraticIntoLinear(TIDSortedElemSet& theElems)
+{
+  vector< const SMDS_MeshNode* > elemNodes(27), subNodes[12], splitNodes[8];
+  vector<const SMDS_MeshElement* > splitElems;
+  list< const SMDS_MeshElement* > elemQueue;
+  list< const SMDS_MeshElement* >::iterator elemIt;
+
+  SMESHDS_Mesh * mesh = GetMeshDS();
+  ElemFeatures *elemType, hexaType(SMDSAbs_Volume), quadType(SMDSAbs_Face), segType(SMDSAbs_Edge);
+  int nbElems, nbNodes;
+
+  TIDSortedElemSet::iterator elemSetIt = theElems.begin();
+  for ( ; elemSetIt != theElems.end(); ++elemSetIt )
+  {
+    elemQueue.clear();
+    elemQueue.push_back( *elemSetIt );
+    for ( elemIt = elemQueue.begin(); elemIt != elemQueue.end(); ++elemIt )
+    {
+      const SMDS_MeshElement* elem = *elemIt;
+      switch( elem->GetEntityType() )
+      {
+      case SMDSEntity_TriQuad_Hexa: // HEX27
+      {
+        elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
+        nbElems  = nbNodes = 8;
+        elemType = & hexaType;
+
+        // get nodes for new elements
+        static int vInd[8][8] = {{ 0,8,20,11,   16,21,26,24 },
+                                 { 1,9,20,8,    17,22,26,21 },
+                                 { 2,10,20,9,   18,23,26,22 },
+                                 { 3,11,20,10,  19,24,26,23 },
+                                 { 16,21,26,24, 4,12,25,15  },
+                                 { 17,22,26,21, 5,13,25,12  },
+                                 { 18,23,26,22, 6,14,25,13  },
+                                 { 19,24,26,23, 7,15,25,14  }};
+        selectNodes( elemNodes, & splitNodes[0], &vInd[0][0], nbElems, nbNodes );
+
+        // add boundary faces to elemQueue
+        static int fInd[6][9] = {{ 0,1,2,3, 8,9,10,11,   20 },
+                                 { 4,5,6,7, 12,13,14,15, 25 },
+                                 { 0,1,5,4, 8,17,12,16,  21 },
+                                 { 1,2,6,5, 9,18,13,17,  22 },
+                                 { 2,3,7,6, 10,19,14,18, 23 },
+                                 { 3,0,4,7, 11,16,15,19, 24 }};
+        selectNodes( elemNodes, & subNodes[0], &fInd[0][0], 6,9, mesh, &elemQueue, SMDSAbs_Face );
+
+        // add boundary segments to elemQueue
+        static int eInd[12][3] = {{ 0,1,8 }, { 1,2,9 }, { 2,3,10 }, { 3,0,11 },
+                                  { 4,5,12}, { 5,6,13}, { 6,7,14 }, { 7,4,15 },
+                                  { 0,4,16}, { 1,5,17}, { 2,6,18 }, { 3,7,19 }};
+        selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 12,3, mesh, &elemQueue, SMDSAbs_Edge );
+        break;
+      }
+      case SMDSEntity_BiQuad_Triangle: // TRIA7
+      {
+        elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
+        nbElems = 3;
+        nbNodes = 4;
+        elemType = & quadType;
+
+        // get nodes for new elements
+        static int fInd[3][4] = {{ 0,3,6,5 }, { 1,4,6,3 }, { 2,5,6,4 }};
+        selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes );
+
+        // add boundary segments to elemQueue
+        static int eInd[3][3] = {{ 0,1,3 }, { 1,2,4 }, { 2,0,5 }};
+        selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 3,3, mesh, &elemQueue, SMDSAbs_Edge );
+        break;
+      }
+      case SMDSEntity_BiQuad_Quadrangle: // QUAD9
+      {
+        elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
+        nbElems = 4;
+        nbNodes = 4;
+        elemType = & quadType;
+
+        // get nodes for new elements
+        static int fInd[4][4] = {{ 0,4,8,7 }, { 1,5,8,4 }, { 2,6,8,5 }, { 3,7,8,6 }};
+        selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes );
+
+        // add boundary segments to elemQueue
+        static int eInd[4][3] = {{ 0,1,4 }, { 1,2,5 }, { 2,3,6 }, { 3,0,7 }};
+        selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 4,3, mesh, &elemQueue, SMDSAbs_Edge );
+        break;
+      }
+      case SMDSEntity_Quad_Edge:
+      {
+        if ( elemIt == elemQueue.begin() )
+          continue; // an elem is in theElems
+        elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
+        nbElems = 2;
+        nbNodes = 2;
+        elemType = & segType;
+
+        // get nodes for new elements
+        static int eInd[2][2] = {{ 0,2 }, { 2,1 }};
+        selectNodes( elemNodes, & splitNodes[0], &eInd[0][0], nbElems, nbNodes );
+        break;
+      }
+      default: continue;
+      } // switch( elem->GetEntityType() )
+
+      // Create new elements
+
+      SMESHDS_SubMesh* subMesh = mesh->MeshElements( elem->getshapeId() );
+
+      splitElems.clear();
+
+      //elemType->SetID( elem->GetID() ); // create an elem with the same ID as a removed one
+      mesh->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false );
+      //splitElems.push_back( AddElement( splitNodes[ 0 ], *elemType ));
+      //elemType->SetID( -1 );
+
+      for ( int iE = 0; iE < nbElems; ++iE )
+        splitElems.push_back( AddElement( splitNodes[ iE ], *elemType ));
+
+
+      ReplaceElemInGroups( elem, splitElems, mesh );
+
+      if ( subMesh )
+        for ( size_t i = 0; i < splitElems.size(); ++i )
+          subMesh->AddElement( splitElems[i] );
+    }
+  }
 }
 
 //=======================================================================
index 1dbed7d..6f75318 100644 (file)
@@ -221,7 +221,7 @@ public:
 
   /*!
    * \brief For hexahedra that will be split into prisms, finds facets to
-   *        split into triangles 
+   *        split into triangles
    *  \param [in,out] theHexas - the hexahedra
    *  \param [in]     theFacetNormal - facet normal
    *  \param [out]    theFacets - the hexahedra and found facet IDs
@@ -230,6 +230,16 @@ public:
                              const gp_Ax1&     theFacetNormal,
                              TFacetOfElem &    theFacets);
 
+  /*!
+   * \brief Split bi-quadratic elements into linear ones without creation of additional nodes
+   *   - bi-quadratic triangle will be split into 3 linear quadrangles;
+   *   - bi-quadratic quadrangle will be split into 4 linear quadrangles;
+   *   - tri-quadratic hexahedron will be split into 8 linear hexahedra;
+   *   Quadratic elements of lower dimension  adjacent to the split bi-quadratic element
+   *   will be split in order to keep the mesh conformal.
+   *  \param elems - elements to split
+   */
+  void SplitBiQuadraticIntoLinear(TIDSortedElemSet& theElems);
 
   enum SmoothMethod { LAPLACIAN = 0, CENTROIDAL };
 
index ed8b783..b334baa 100644 (file)
@@ -141,6 +141,7 @@ SET(_moc_HEADERS
   SMESHGUI_Add0DElemsOnAllNodesDlg.h
   SMESHGUI_FieldSelectorWdg.h
   SMESHGUI_DisplayEntitiesDlg.h
+  SMESHGUI_SplitBiQuad.h
 )
 
 # header files / no moc processing
@@ -249,6 +250,7 @@ SET(_other_SOURCES
   SMESHGUI_FileValidator.cxx
   SMESHGUI_FieldSelectorWdg.cxx
   SMESHGUI_DisplayEntitiesDlg.cxx
+  SMESHGUI_SplitBiQuad.cxx
 )
 
 # sources / to compile
index 1214bf1..6271fe8 100644 (file)
@@ -82,6 +82,7 @@
 #include "SMESHGUI_TranslationDlg.h"
 #include "SMESHGUI_TransparencyDlg.h"
 #include "SMESHGUI_DisplayEntitiesDlg.h"
+#include "SMESHGUI_SplitBiQuad.h"
 
 #include "SMESHGUI_FilterUtils.h"
 #include "SMESHGUI_GEOMGenUtils.h"
@@ -2853,6 +2854,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID )
       }
       break;
     }
+  case SMESHOp::OpSplitBiQuadratic:
   case SMESHOp::OpConvertMeshToQuadratic:
   case SMESHOp::OpCreateBoundaryElements: // create 2D mesh from 3D
   case SMESHOp::OpReorientFaces:
@@ -3942,6 +3944,7 @@ void SMESHGUI::initialize( CAM_Application* app )
   createSMESHAction( SMESHOp::OpUnionOfTriangles,       "UNION",           "ICON_UNIONTRI" );
   createSMESHAction( SMESHOp::OpCuttingOfQuadrangles,   "CUT",             "ICON_CUTQUAD" );
   createSMESHAction( SMESHOp::OpSplitVolumes,           "SPLIT_TO_TETRA",  "ICON_SPLIT_TO_TETRA" );
+  createSMESHAction( SMESHOp::OpSplitBiQuadratic,       "SPLIT_BIQUAD",    "ICON_SPLIT_BIQUAD" );
   createSMESHAction( SMESHOp::OpSmoothing,              "SMOOTH",          "ICON_DLG_SMOOTHING" );
   createSMESHAction( SMESHOp::OpExtrusion,              "EXTRUSION",       "ICON_EXTRUSION" );
   createSMESHAction( SMESHOp::OpExtrusionAlongAPath,    "EXTRUSION_ALONG", "ICON_EXTRUSION_ALONG" );
@@ -4177,6 +4180,7 @@ void SMESHGUI::initialize( CAM_Application* app )
   createMenu( SMESHOp::OpUnionOfTriangles,       modifyId, -1 );
   createMenu( SMESHOp::OpCuttingOfQuadrangles,   modifyId, -1 );
   createMenu( SMESHOp::OpSplitVolumes,           modifyId, -1 );
+  createMenu( SMESHOp::OpSplitBiQuadratic,       modifyId, -1 );
   createMenu( SMESHOp::OpSmoothing,              modifyId, -1 );
   createMenu( SMESHOp::OpExtrusion,              modifyId, -1 );
   createMenu( SMESHOp::OpExtrusionAlongAPath ,   modifyId, -1 );
@@ -4312,6 +4316,7 @@ void SMESHGUI::initialize( CAM_Application* app )
   createTool( SMESHOp::OpUnionOfTriangles,       modifyTb );
   createTool( SMESHOp::OpCuttingOfQuadrangles,   modifyTb );
   createTool( SMESHOp::OpSplitVolumes,           modifyTb );
+  createTool( SMESHOp::OpSplitBiQuadratic,       modifyTb );
   createTool( SMESHOp::OpSmoothing,              modifyTb );
   createTool( SMESHOp::OpExtrusion,              modifyTb );
   createTool( SMESHOp::OpExtrusionAlongAPath,    modifyTb );
@@ -5480,6 +5485,9 @@ LightApp_Operation* SMESHGUI::createOperation( const int id ) const
   // to do : create operation here
   switch( id )
   {
+    case SMESHOp::OpSplitBiQuadratic:
+      op = new SMESHGUI_SplitBiQuadOp();
+    break;
     case SMESHOp::OpConvertMeshToQuadratic:
       op = new SMESHGUI_ConvToQuadOp();
     break;
index bc2629a..cc60fc4 100644 (file)
@@ -346,6 +346,7 @@ SMESHGUI_ConvToQuadOp::DestinationMesh( const SMESH::SMESH_IDSource_var& idSourc
                    nbElemOfType[SMDSEntity_Quad_Tetra     ] ||
                    nbElemOfType[SMDSEntity_Quad_Hexa      ] ||
                    nbElemOfType[SMDSEntity_Quad_Pyramid   ] ||
+                   nbElemOfType[SMDSEntity_Quad_Polygon   ] ||
                    nbElemOfType[SMDSEntity_Quad_Penta     ] );
 
   bool hasLin  = ( nbElemOfType[SMDSEntity_Edge      ] ||
@@ -354,6 +355,7 @@ SMESHGUI_ConvToQuadOp::DestinationMesh( const SMESH::SMESH_IDSource_var& idSourc
                    nbElemOfType[SMDSEntity_Tetra     ] ||
                    nbElemOfType[SMDSEntity_Hexa      ] ||
                    nbElemOfType[SMDSEntity_Pyramid   ] ||
+                   nbElemOfType[SMDSEntity_Polygon   ] ||
                    nbElemOfType[SMDSEntity_Penta     ] );
 
   int tgtType = 0;
index cd28f8b..9f492bf 100644 (file)
@@ -176,6 +176,7 @@ namespace SMESHOp {
     OpPatternMapping         = 4512,   // MENU MODIFICATION - PATTERN MAPPING
     OpConvertMeshToQuadratic = 4513,   // MENU MODIFICATION - CONVERT TO/FROM QUADRATIC
     OpCreateBoundaryElements = 4514,   // MENU MODIFICATION - CREATE BOUNDARY ELEMENTS
+    OpSplitBiQuadratic       = 4515,   // MENU MODIFICATION - SPLIT BI-QUADRATIC TO LINEAR
     // Measurements -------------------//--------------------------------
     OpPropertiesLength       = 5000,   // MENU MEASUREMENTS - BASIC PROPERTIES - LENGTH
     OpPropertiesArea         = 5001,   // MENU MEASUREMENTS - BASIC PROPERTIES - AREA
diff --git a/src/SMESHGUI/SMESHGUI_SplitBiQuad.cxx b/src/SMESHGUI/SMESHGUI_SplitBiQuad.cxx
new file mode 100644 (file)
index 0000000..a35f752
--- /dev/null
@@ -0,0 +1,255 @@
+// Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+// SMESH SMESHGUI : GUI for SMESH component
+// File   : SMESHGUI_SplitBiQuad.h
+// Author : Open CASCADE S.A.S.
+//
+
+#include "SMESHGUI_SplitBiQuad.h"
+
+#include "SMESHGUI.h"
+#include "SMESHGUI_Utils.h"
+#include "SMESH_LogicalFilter.hxx"
+#include "SMESH_TypeFilter.hxx"
+
+#include <SALOMEconfig.h>
+#include CORBA_SERVER_HEADER(SMESH_MeshEditor)
+
+#include <LightApp_UpdateFlags.h>
+#include <SUIT_MessageBox.h>
+#include <SUIT_OverrideCursor.h>
+#include <SalomeApp_Tools.h>
+
+#include <QStringList>
+#include <QGridLayout>
+
+//================================================================================
+/*!
+ * \brief Dialog constructor
+ */
+//================================================================================
+
+SMESHGUI_SplitBiQuadDlg::SMESHGUI_SplitBiQuadDlg()
+  : SMESHGUI_Dialog( 0, /*modal=*/false, /*allowResize=*/true )
+{
+  setWindowTitle( tr( "CAPTION" ) );
+  setObjectPixmap( "SMESH", tr( "ICON_SELECT" ) );
+  createObject( tr( "MESH" ), mainFrame(), 0 );
+
+  QGridLayout* aLay = new QGridLayout( mainFrame() );
+  aLay->setMargin( 5 );
+  aLay->setSpacing( 5 );
+
+  aLay->addWidget( objectWg( 0,  Label ),   0, 0 );
+  //aLay->addWidget( objectWg( 0,  Btn ),     0, 1 );
+  aLay->addWidget( objectWg( 0,  Control ), 0, 1 );
+  objectWg( 0,  Btn )->hide();
+}
+
+//================================================================================
+/*!
+ * \brief Dialog destructor
+ */
+//================================================================================
+
+SMESHGUI_SplitBiQuadDlg::~SMESHGUI_SplitBiQuadDlg()
+{
+}
+
+//================================================================================
+/*!
+ * \brief SMESHGUI_SplitBiQuadOp constructor
+ */
+//================================================================================
+
+SMESHGUI_SplitBiQuadOp::SMESHGUI_SplitBiQuadOp()
+  : SMESHGUI_SelectionOp(), myDlg( 0 )
+{
+}
+
+//================================================================================
+/*!
+ * \brief SMESHGUI_SplitBiQuadOp destructor
+ */
+//================================================================================
+
+SMESHGUI_SplitBiQuadOp::~SMESHGUI_SplitBiQuadOp()
+{
+  if ( myDlg ) delete myDlg;
+}
+
+//================================================================================
+/*!
+ * \brief Gets dialog of this operation
+  * \retval LightApp_Dialog* - pointer to dialog of this operation
+*/
+//================================================================================
+
+LightApp_Dialog* SMESHGUI_SplitBiQuadOp::dlg() const
+{
+  return myDlg;
+}
+
+//================================================================================
+/*!
+ * \brief Creates dialog if necessary and shows it
+ *
+ * Virtual method redefined from base class called when operation is started creates
+ * dialog if necessary and shows it, activates selection
+ */
+//================================================================================
+
+void SMESHGUI_SplitBiQuadOp::startOperation()
+{
+  if( !myDlg )
+  {
+    myDlg = new SMESHGUI_SplitBiQuadDlg();
+  }
+  myHelpFileName = "split_biquad_to_linear_page.html";
+
+  SMESHGUI_SelectionOp::startOperation();
+
+  myDlg->activateObject( 0 );
+  myDlg->show();
+
+  selectionDone();
+}
+
+//================================================================================
+/*!
+ * \brief Updates dialog's look and feel
+ *
+ * Virtual method redefined from the base class updates dialog's look and feel
+ */
+//================================================================================
+
+// void SMESHGUI_SplitBiQuadOp::selectionDone()
+// {
+//   if ( !dlg()->isVisible() )
+//     return;
+
+//   SMESHGUI_SelectionOp::selectionDone();
+// }
+
+//================================================================================
+/*!
+ * \brief Creates selection filter
+  * \param theId - identifier of current selection widget
+  * \retval SUIT_SelectionFilter* - pointer to the created filter or null
+ *
+ * Creates selection filter in accordance with identifier of current selection widget
+ */
+//================================================================================
+
+SUIT_SelectionFilter* SMESHGUI_SplitBiQuadOp::createFilter( const int theId ) const
+{
+  if ( theId != 0 )
+    return 0;
+
+  QList<SUIT_SelectionFilter*> filters;
+  filters << new SMESH_TypeFilter( SMESH::IDSOURCE_FACE );
+  filters << new SMESH_TypeFilter( SMESH::IDSOURCE_VOLUME );
+  return new SMESH_LogicalFilter( filters,
+                                  SMESH_LogicalFilter::LO_OR,
+                                  /*takeOwnership=*/true );
+}
+
+//================================================================================
+/*!
+ * \brief Edits mesh
+ *
+ * Virtual slot redefined from the base class called when "Apply" button is clicked
+ */
+//================================================================================
+
+bool SMESHGUI_SplitBiQuadOp::onApply()
+{
+  SUIT_OverrideCursor aWaitCursor;
+
+  LightApp_Dialog::SelectedObjects selection;
+  myDlg->objectSelection( selection );
+  if ( selection.empty() || selection[0].empty() )
+  {
+    SUIT_MessageBox::warning( myDlg, tr( "SMESH_WRN_WARNING" ), tr("MESH_IS_NOT_SELECTED") );
+    return false;
+  }
+  QStringList& entries = selection[0];
+
+  SMESH::SMESH_Mesh_var mesh;
+  SMESH::ListOfIDSources_var idSource = new SMESH::ListOfIDSources();
+  idSource->length( entries.count() );
+
+  int nbObj = 0;
+  for ( int i = 0; i < entries.count() ; ++i )
+  {
+    _PTR(SObject) pObj = studyDS()->FindObjectID( entries[i].toLatin1().data() );
+    SMESH::SMESH_IDSource_var obj = SMESH::SObjectToInterface<SMESH::SMESH_IDSource>( pObj );
+    if( !CORBA::is_nil( obj ))
+    {
+      idSource[ nbObj++ ] = obj;
+      SMESH::SMESH_Mesh_var m = obj->GetMesh();
+      if ( !mesh->_is_nil() && mesh->GetId() != m->GetId() )
+      {
+        SUIT_MessageBox::warning( myDlg, tr( "SMESH_WRN_WARNING" ), tr("DIFFERENT_MESHES") );
+        return false;
+      }
+      mesh = m;
+    }
+  }
+  if ( CORBA::is_nil( mesh ))
+  {
+    SUIT_MessageBox::warning( myDlg, tr( "SMESH_WRN_WARNING" ), tr("REF_IS_NULL") );
+    return false;
+  }
+  if ( nbObj == 0 )
+  {
+    SUIT_MessageBox::warning( myDlg, tr( "SMESH_WRN_WARNING" ), tr("MESH_IS_NOT_SELECTED") );
+    return false;
+  }
+  idSource->length( nbObj );
+
+  bool aResult = false;
+
+  try
+  {
+    SMESH::SMESH_MeshEditor_var aEditor = mesh->GetMeshEditor();
+    aResult = true;
+    aEditor->SplitBiQuadraticIntoLinear( idSource );
+  }
+  catch ( const SALOME::SALOME_Exception& S_ex )
+  {
+    SalomeApp_Tools::QtCatchCorbaException( S_ex );
+    aResult = false;
+  }
+  catch ( ... )
+  {
+    aResult = false;
+  }
+  if( aResult )
+  {
+    SMESHGUI::Modified();
+    update( UF_ObjBrowser | UF_Model | UF_Viewer );
+    selectionDone();
+  }
+  return aResult;
+}
diff --git a/src/SMESHGUI/SMESHGUI_SplitBiQuad.h b/src/SMESHGUI/SMESHGUI_SplitBiQuad.h
new file mode 100644 (file)
index 0000000..13cbd71
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+// SMESH SMESHGUI : GUI for SMESH component
+// File   : SMESHGUI_SplitBiQuad.h
+// Author : Open CASCADE S.A.S.
+//
+#ifndef SMESHGUI_SplitBiQuad_H
+#define SMESHGUI_SplitBiQuad_H
+
+#include "SMESH_SMESHGUI.hxx"
+#include "SMESHGUI_Dialog.h"
+#include "SMESHGUI_SelectionOp.h"
+
+class SMESHGUI_SplitBiQuadOp;
+
+/*!
+ * \brief Dialog performing SMESH_MeshEditor::SplitBiQuadraticIntoLinear()
+ */
+class SMESHGUI_EXPORT SMESHGUI_SplitBiQuadDlg : public SMESHGUI_Dialog
+{ 
+  Q_OBJECT       
+        
+    public:
+  SMESHGUI_SplitBiQuadDlg();
+  virtual ~SMESHGUI_SplitBiQuadDlg();
+
+  friend class SMESHGUI_SplitBiQuadOp;
+};
+
+class SMESHGUI_EXPORT SMESHGUI_SplitBiQuadOp : public SMESHGUI_SelectionOp
+{
+  Q_OBJECT
+
+public:      
+  SMESHGUI_SplitBiQuadOp();
+  virtual ~SMESHGUI_SplitBiQuadOp();
+  
+  virtual LightApp_Dialog*       dlg() const;  
+
+protected:
+  virtual void                   startOperation();
+  //virtual void                   selectionDone();
+  virtual SUIT_SelectionFilter*  createFilter( const int ) const;
+
+protected slots:
+  virtual bool                   onApply();
+
+private:
+  SMESHGUI_SplitBiQuadDlg*       myDlg;
+};
+
+#endif // SMESHGUI_SplitBiQuad_H
index c13a65e..a0c988e 100644 (file)
             <source>ICON_SPLIT_TO_TETRA</source>
             <translation>split_into_tetra.png</translation>
         </message>
+        <message>
+            <source>ICON_SPLIT_BIQUAD</source>
+            <translation>split_biquad.png</translation>
+        </message>
        <message>
             <source>ICON_MEASURE_LENGTH</source>
             <translation>mesh_measure_length.png</translation>
index 45fef37..3bdd72e 100644 (file)
         <translation>Split Volumes</translation>
     </message>
     <message>
+        <source>MEN_SPLIT_BIQUAD</source>
+        <translation>Split bi-quadratic into linear</translation>
+    </message>
+    <message>
+        <source>TOP_SPLIT_BIQUAD</source>
+        <translation>Split bi-quadratic into linear</translation>
+    </message>
+    <message>
+        <source>STB_SPLIT_BIQUAD</source>
+        <translation>Split bi-quadratic into linear</translation>
+    </message>
+    <message>
         <source>MESHERS_FILE_CANT_OPEN</source>
         <translation>Can not open resource file</translation>
     </message>
@@ -4901,6 +4913,33 @@ Do you want to restore original sub-mesh priority?</translation>
     </message>
 </context>
 <context>
+    <name>SMESHGUI_SplitBiQuadDlg</name>
+    <message>
+        <source>CAPTION</source>
+        <translation>Split bi-qiadratic into linear</translation>
+    </message>
+    <message>
+        <source>MESH</source>
+        <translation>Mesh, Group or Sub-mesh</translation>
+    </message>
+</context>
+<context>
+    <name>SMESHGUI_SplitBiQuadOp</name>
+    <message>
+        <source>MESH_IS_NOT_SELECTED</source>
+        <translation>No object to split is selected.
+Please specify it and try again</translation>
+    </message>
+    <message>
+        <source>REF_IS_NULL</source>
+        <translation>No valid mesh object selected</translation>
+    </message>
+    <message>
+        <source>DIFFERENT_MESHES</source>
+        <translation>Selected objects belong to different meshes</translation>
+    </message>
+</context>
+<context>
     <name>SMESHGUI_ConvToQuadDlg</name>
     <message>
         <source>CAPTION</source>
index f0f4d52..a64c4ba 100644 (file)
@@ -66,8 +66,8 @@ namespace
 
   struct InPoint
   {
-    int _a, _b;
-    double _param;
+    int _a, _b;    // coordinates
+    double _param; // param on EDGE
     InPoint(int x, int y, double param) : _a(x), _b(y), _param(param) {}
     InPoint() : _a(0), _b(0), _param(0) {}
 
@@ -773,7 +773,7 @@ namespace
       inPoints[0]._edges.clear();
     }
 
-    // Divide InSegment's into BndSeg's
+    // Divide InSegment's into BndSeg's (each BndSeg corresponds to one MA edge)
 
     vector< BndSeg > bndSegs;
     bndSegs.reserve( inSegments.size() * 3 );
@@ -791,25 +791,26 @@ namespace
       inPntChecked[ ip0 ] = false;
 
       // segments of InSegment's
-      size_t nbMaEdges = inSeg._edges.size();
+      const size_t nbMaEdges = inSeg._edges.size();
       switch ( nbMaEdges ) {
       case 0: // "around" circle center
         bndSegs.push_back( BndSeg( &inSeg, 0, inSeg._p1->_param )); break;
       case 1:
         bndSegs.push_back( BndSeg( &inSeg, inSeg._edges.back(), inSeg._p1->_param )); break;
       default:
-        vector< double > len;
-        len.push_back(0);
-        for ( e = inSeg._edges.rbegin(); e != inSeg._edges.rend(); ++e )
-          len.push_back( len.back() + length( *e ));
-
+        gp_XY inSegDir( inSeg._p1->_a - inSeg._p0->_a,
+                        inSeg._p1->_b - inSeg._p0->_b );
+        const double inSegLen2 = inSegDir.SquareModulus();
         e = inSeg._edges.rbegin();
-        for ( size_t l = 1; l < len.size(); ++e, ++l )
+        for ( size_t iE = 1; iE < nbMaEdges; ++e, ++iE )
         {
-          double dl = len[l] / len.back();
-          double u  = dl * inSeg._p1->_param + ( 1. - dl ) * inSeg._p0->_param;
+          gp_XY toMA( (*e)->vertex0()->x() - inSeg._p0->_a,
+                      (*e)->vertex0()->y() - inSeg._p0->_b );
+          double r = toMA * inSegDir / inSegLen2;
+          double u = r * inSeg._p1->_param + ( 1. - r ) * inSeg._p0->_param;
           bndSegs.push_back( BndSeg( &inSeg, *e, u ));
         }
+        bndSegs.push_back( BndSeg( &inSeg, *e, inSeg._p1->_param ));
       }
       // segments around 2nd concave point
       size_t ip1 = inSeg._p1->index( inPoints );
index 157983e..c0e4963 100644 (file)
@@ -2086,7 +2086,7 @@ void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems,
  */
 //================================================================================
 
-void SMESH_MeshEditor_i::SplitHexahedraIntoPrisms (SMESH::SMESH_IDSource_ptr  elems,
+void SMESH_MeshEditor_i::SplitHexahedraIntoPrismsSMESH::SMESH_IDSource_ptr  elems,
                                                    const SMESH::PointStruct & startHexPoint,
                                                    const SMESH::DirStruct&    facetToSplitNormal,
                                                    CORBA::Short               methodFlags,
@@ -2138,6 +2138,44 @@ void SMESH_MeshEditor_i::SplitHexahedraIntoPrisms (SMESH::SMESH_IDSource_ptr  el
   SMESH_CATCH( SMESH::throwCorbaException );
 }
 
+//================================================================================
+/*!
+ * \brief Split bi-quadratic elements into linear ones without creation of additional nodes:
+ *   - bi-quadratic triangle will be split into 3 linear quadrangles;
+ *   - bi-quadratic quadrangle will be split into 4 linear quadrangles;
+ *   - tri-quadratic hexahedron will be split into 8 linear hexahedra.
+ *   Quadratic elements of lower dimension  adjacent to the split bi-quadratic element
+ *   will be split in order to keep the mesh conformal.
+ *  \param elems - elements to split
+ */
+//================================================================================
+
+void SMESH_MeshEditor_i::SplitBiQuadraticIntoLinear(const SMESH::ListOfIDSources& theElems)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH_TRY;
+  initData();
+
+  TIDSortedElemSet elemSet;
+  for ( size_t i = 0; i < theElems.length(); ++i )
+  {
+    SMESH::SMESH_IDSource_ptr elems = theElems[i].in();
+    SMESH::SMESH_Mesh_var      mesh = elems->GetMesh();
+    if ( mesh->GetId() != myMesh_i->GetId() )
+      THROW_SALOME_CORBA_EXCEPTION("Wrong mesh of IDSource", SALOME::BAD_PARAM);
+
+    idSourceToSet( elems, getMeshDS(), elemSet, SMDSAbs_All );
+  }
+  getEditor().SplitBiQuadraticIntoLinear( elemSet );
+
+  declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
+
+  TPythonDump() << this << ".SplitBiQuadraticIntoLinear( "
+                << theElems << " )";
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+}
+
 //=======================================================================
 //function : Smooth
 //purpose  :
index 6d25784..560afae 100644 (file)
@@ -221,7 +221,7 @@ public:
                              CORBA::Boolean                 outsideNormal)
     throw (SALOME::SALOME_Exception);
 
-  // Split/Join faces
+  // Split/Join
   CORBA::Boolean TriToQuad       (const SMESH::long_array &   IDsOfElements,
                                   SMESH::NumericalFunctor_ptr Criterion,
                                   CORBA::Double               MaxAngle)
@@ -256,6 +256,8 @@ public:
                                           CORBA::Short               methodFlags,
                                           CORBA::Boolean             allDomains)
     throw (SALOME::SALOME_Exception);
+  void           SplitBiQuadraticIntoLinear(const SMESH::ListOfIDSources& elems)
+    throw (SALOME::SALOME_Exception);
 
   CORBA::Boolean Smooth(const SMESH::long_array &              IDsOfElements,
                         const SMESH::long_array &              IDsOfFixedNodes,
index 430b1fb..3e3b675 100644 (file)
@@ -689,15 +689,17 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
 
     ## Creates a criterion by the given parameters
     #  \n Criterion structures allow to define complex filters by combining them with logical operations (AND / OR) (see example below)
-    #  @param elementType the type of elements(NODE, EDGE, FACE, VOLUME)
-    #  @param CritType the type of criterion (FT_Taper, FT_Area, FT_RangeOfIds, FT_LyingOnGeom etc.)
-    #  @param Compare  belongs to {FT_LessThan, FT_MoreThan, FT_EqualTo}
+    #  @param elementType the type of elements(SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME)
+    #  @param CritType the type of criterion (SMESH.FT_Taper, SMESH.FT_Area, etc.)
+    #          Type SMESH.FunctorType._items in the Python Console to see all values.
+    #          Note that the items starting from FT_LessThan are not suitable for CritType.
+    #  @param Compare  belongs to {SMESH.FT_LessThan, SMESH.FT_MoreThan, SMESH.FT_EqualTo}
     #  @param Threshold the threshold value (range of ids as string, shape, numeric)
-    #  @param UnaryOp  FT_LogicalNOT or FT_Undefined
-    #  @param BinaryOp a binary logical operation FT_LogicalAND, FT_LogicalOR or
-    #                  FT_Undefined (must be for the last criterion of all criteria)
-    #  @param Tolerance the tolerance used by FT_BelongToGeom, FT_BelongToSurface,
-    #         FT_LyingOnGeom, FT_CoplanarFaces criteria
+    #  @param UnaryOp  SMESH.FT_LogicalNOT or SMESH.FT_Undefined
+    #  @param BinaryOp a binary logical operation SMESH.FT_LogicalAND, SMESH.FT_LogicalOR or
+    #                  SMESH.FT_Undefined
+    #  @param Tolerance the tolerance used by SMESH.FT_BelongToGeom, SMESH.FT_BelongToSurface,
+    #         SMESH.FT_LyingOnGeom, SMESH.FT_CoplanarFaces criteria
     #  @return SMESH.Filter.Criterion
     #
     #  <a href="../tui_filters_page.html#combining_filters">Example of Criteria usage</a>
@@ -874,13 +876,15 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
         return aCriterion
 
     ## Creates a filter with the given parameters
-    #  @param elementType the type of elements in the group
-    #  @param CritType the type of criterion ( FT_Taper, FT_Area, FT_RangeOfIds, FT_LyingOnGeom etc. )
-    #  @param Compare  belongs to {FT_LessThan, FT_MoreThan, FT_EqualTo}
-    #  @param Threshold the threshold value (range of id ids as string, shape, numeric)
-    #  @param UnaryOp  FT_LogicalNOT or FT_Undefined
-    #  @param Tolerance the tolerance used by FT_BelongToGeom, FT_BelongToSurface,
-    #         FT_LyingOnGeom, FT_CoplanarFaces and FT_EqualNodes criteria
+    #  @param elementType the type of elements (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME)
+    #  @param CritType the type of criterion (SMESH.FT_Taper, SMESH.FT_Area, etc.)
+    #          Type SMESH.FunctorType._items in the Python Console to see all values.
+    #          Note that the items starting from FT_LessThan are not suitable for CritType.
+    #  @param Compare  belongs to {SMESH.FT_LessThan, SMESH.FT_MoreThan, SMESH.FT_EqualTo}
+    #  @param Threshold the threshold value (range of ids as string, shape, numeric)
+    #  @param UnaryOp  SMESH.FT_LogicalNOT or SMESH.FT_Undefined
+    #  @param Tolerance the tolerance used by SMESH.FT_BelongToGeom, SMESH.FT_BelongToSurface,
+    #         SMESH.FT_LyingOnGeom, SMESH.FT_CoplanarFaces and SMESH.FT_EqualNodes criteria
     #  @param mesh the mesh to initialize the filter with
     #  @return SMESH_Filter
     #
@@ -923,7 +927,9 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
         return aFilter
 
     ## Creates a numerical functor by its type
-    #  @param theCriterion FT_...; functor type
+    #  @param theCriterion functor type - an item of SMESH.FunctorType enumeration.
+    #          Type SMESH.FunctorType._items in the Python Console to see all items.
+    #          Note that not all items corresponds to numerical functors.
     #  @return SMESH_NumericalFunctor
     #  @ingroup l1_controls
     def GetFunctor(self,theCriterion):
@@ -1828,7 +1834,8 @@ class Mesh:
     # ----------------------
 
     ## Creates an empty mesh group
-    #  @param elementType the type of elements in the group
+    #  @param elementType the type of elements in the group; either of 
+    #         (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME)
     #  @param name the name of the mesh group
     #  @return SMESH_Group
     #  @ingroup l2_grps_create
@@ -1851,8 +1858,9 @@ class Mesh:
     #  the name is the same as the geometrical group name
     #  @param grp  a geometrical group, a vertex, an edge, a face or a solid
     #  @param name the name of the mesh group
-    #  @param typ  the type of elements in the group. If not set, it is
-    #              automatically detected by the type of the geometry
+    #  @param typ  the type of elements in the group; either of 
+    #         (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME). If not set, it is
+    #         automatically detected by the type of the geometry
     #  @return SMESH_GroupOnGeom
     #  @ingroup l2_grps_create
     def GroupOnGeom(self, grp, name="", typ=None):
@@ -1887,7 +1895,8 @@ class Mesh:
     ## Creates a mesh group with given \a name based on the \a filter which
     ## is a special type of group dynamically updating it's contents during
     ## mesh modification
-    #  @param typ  the type of elements in the group
+    #  @param typ  the type of elements in the group; either of 
+    #         (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME).
     #  @param name the name of the mesh group
     #  @param filter the filter defining group contents
     #  @return SMESH_GroupOnFilter
@@ -1897,7 +1906,8 @@ class Mesh:
 
     ## Creates a mesh group by the given ids of elements
     #  @param groupName the name of the mesh group
-    #  @param elementType the type of elements in the group
+    #  @param elementType the type of elements in the group; either of 
+    #         (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME).
     #  @param elemIDs the list of ids
     #  @return SMESH_Group
     #  @ingroup l2_grps_create
@@ -1913,13 +1923,15 @@ class Mesh:
 
     ## Creates a mesh group by the given conditions
     #  @param groupName the name of the mesh group
-    #  @param elementType the type of elements in the group
-    #  @param CritType the type of criterion( FT_Taper, FT_Area, FT_RangeOfIds, FT_LyingOnGeom etc. )
-    #  @param Compare belongs to {FT_LessThan, FT_MoreThan, FT_EqualTo}
-    #  @param Threshold the threshold value (range of id ids as string, shape, numeric)
-    #  @param UnaryOp FT_LogicalNOT or FT_Undefined
-    #  @param Tolerance the tolerance used by FT_BelongToGeom, FT_BelongToSurface,
-    #         FT_LyingOnGeom, FT_CoplanarFaces criteria
+    #  @param elementType the type of elements(SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME)
+    #  @param CritType the type of criterion (SMESH.FT_Taper, SMESH.FT_Area, etc.)
+    #          Type SMESH.FunctorType._items in the Python Console to see all values.
+    #          Note that the items starting from FT_LessThan are not suitable for CritType.
+    #  @param Compare  belongs to {SMESH.FT_LessThan, SMESH.FT_MoreThan, SMESH.FT_EqualTo}
+    #  @param Threshold the threshold value (range of ids as string, shape, numeric)
+    #  @param UnaryOp  SMESH.FT_LogicalNOT or SMESH.FT_Undefined
+    #  @param Tolerance the tolerance used by SMESH.FT_BelongToGeom, SMESH.FT_BelongToSurface,
+    #         SMESH.FT_LyingOnGeom, SMESH.FT_CoplanarFaces criteria
     #  @return SMESH_GroupOnFilter
     #  @ingroup l2_grps_create
     def MakeGroup(self,
@@ -1977,10 +1989,22 @@ class Mesh:
 
     ## Gets the list of groups existing in the mesh in the order
     #  of creation (starting from the oldest one)
+    #  @param elemType type of elements the groups contain; either of 
+    #         (SMESH.ALL, SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME);
+    #         by default groups of elements of all types are returned
     #  @return a sequence of SMESH_GroupBase
     #  @ingroup l2_grps_create
-    def GetGroups(self):
-        return self.mesh.GetGroups()
+    def GetGroups(self, elemType = SMESH.ALL):
+        groups = self.mesh.GetGroups()
+        if elemType == SMESH.ALL:
+            return groups
+        typedGroups = []
+        for g in groups:
+            if g.GetType() == elemType:
+                typedGroups.append( g )
+                pass
+            pass
+        return typedGroups
 
     ## Gets the number of groups existing in the mesh
     #  @return the quantity of groups as an integer value
@@ -1998,6 +2022,25 @@ class Mesh:
             names.append(group.GetName())
         return names
 
+    ## Finds groups by name and type
+    #  @param name name of the group of interest
+    #  @param elemType type of elements the groups contain; either of 
+    #         (SMESH.ALL, SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME);
+    #         by default one group of any type of elements is returned
+    #         if elemType == SMESH.ALL then all groups of any type are returned
+    #  @return a list of SMESH_GroupBase's
+    #  @ingroup l2_grps_create
+    def GetGroupByName(self, name, elemType = None):
+        groups = []
+        for group in self.GetGroups():
+            if group.GetName() == name:
+                if elemType is None:
+                    return [group]
+                if ( elemType == SMESH.ALL or 
+                     group.GetType() == elemType ):
+                    groups.append( group )
+        return groups
+
     ## Produces a union of two groups.
     #  A new group is created. All mesh elements that are
     #  present in the initial groups are added to the new one
@@ -2049,7 +2092,8 @@ class Mesh:
     ##
     #  Create a standalone group of entities basing on nodes of other groups.
     #  \param groups - list of groups, sub-meshes or filters, of any type.
-    #  \param elemType - a type of elements to include to the new group.
+    #  \param elemType - a type of elements to include to the new group; either of 
+    #         (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME).
     #  \param name - a name of the new group.
     #  \param nbCommonNodes - a criterion of inclusion of an element to the new group
     #         basing on number of element nodes common with reference \a groups.
@@ -2134,9 +2178,17 @@ class Mesh:
 
     ## Wrap a list of IDs of elements or nodes into SMESH_IDSource which
     #  can be passed as argument to a method accepting mesh, group or sub-mesh
+    #  @param ids list of IDs
+    #  @param elemType type of elements; this parameter is used to distinguish
+    #         IDs of nodes from IDs of elements; by default ids are treated as
+    #         IDs of elements; use SMESH.NODE if ids are IDs of nodes.
     #  @return an instance of SMESH_IDSource
+    #  @warning call UnRegister() for the returned object as soon as it is no more useful:
+    #          idSrc = mesh.GetIDSource( [1,3,5], SMESH.NODE )
+    #          mesh.DoSomething( idSrc )
+    #          idSrc.UnRegister()
     #  @ingroup l1_auxiliary
-    def GetIDSource(self, ids, elemType):
+    def GetIDSource(self, ids, elemType = SMESH.ALL):
         return self.editor.MakeIDSource(ids, elemType)
 
 
@@ -2182,7 +2234,7 @@ class Mesh:
 
     ## Returns the number of edges with the given order in the mesh
     #  @param elementOrder the order of elements:
-    #         ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC
+    #         SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC
     #  @return an integer value
     #  @ingroup l1_meshinfo
     def NbEdgesOfOrder(self, elementOrder):
@@ -2196,7 +2248,7 @@ class Mesh:
 
     ## Returns the number of faces with the given order in the mesh
     #  @param elementOrder the order of elements:
-    #         ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC
+    #         SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC
     #  @return an integer value
     #  @ingroup l1_meshinfo
     def NbFacesOfOrder(self, elementOrder):
@@ -2210,7 +2262,7 @@ class Mesh:
 
     ## Returns the number of triangles with the given order in the mesh
     #  @param elementOrder is the order of elements:
-    #         ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC
+    #         SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC
     #  @return an integer value
     #  @ingroup l1_meshinfo
     def NbTrianglesOfOrder(self, elementOrder):
@@ -2230,7 +2282,7 @@ class Mesh:
 
     ## Returns the number of quadrangles with the given order in the mesh
     #  @param elementOrder the order of elements:
-    #         ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC
+    #         SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC
     #  @return an integer value
     #  @ingroup l1_meshinfo
     def NbQuadranglesOfOrder(self, elementOrder):
@@ -2243,6 +2295,8 @@ class Mesh:
         return self.mesh.NbBiQuadQuadrangles()
 
     ## Returns the number of polygons of given order in the mesh
+    #  @param elementOrder the order of elements:
+    #         SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC
     #  @return an integer value
     #  @ingroup l1_meshinfo
     def NbPolygons(self, elementOrder = SMESH.ORDER_ANY):
@@ -2256,7 +2310,7 @@ class Mesh:
 
     ## Returns the number of volumes with the given order in the mesh
     #  @param elementOrder  the order of elements:
-    #         ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC
+    #         SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC
     #  @return an integer value
     #  @ingroup l1_meshinfo
     def NbVolumesOfOrder(self, elementOrder):
@@ -2270,7 +2324,7 @@ class Mesh:
 
     ## Returns the number of tetrahedrons with the given order in the mesh
     #  @param elementOrder  the order of elements:
-    #         ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC
+    #         SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC
     #  @return an integer value
     #  @ingroup l1_meshinfo
     def NbTetrasOfOrder(self, elementOrder):
@@ -2284,7 +2338,7 @@ class Mesh:
 
     ## Returns the number of hexahedrons with the given order in the mesh
     #  @param elementOrder  the order of elements:
-    #         ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC
+    #         SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC
     #  @return an integer value
     #  @ingroup l1_meshinfo
     def NbHexasOfOrder(self, elementOrder):
@@ -2304,7 +2358,7 @@ class Mesh:
 
     ## Returns the number of pyramids with the given order in the mesh
     #  @param elementOrder  the order of elements:
-    #         ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC
+    #         SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC
     #  @return an integer value
     #  @ingroup l1_meshinfo
     def NbPyramidsOfOrder(self, elementOrder):
@@ -2318,7 +2372,7 @@ class Mesh:
 
     ## Returns the number of prisms with the given order in the mesh
     #  @param elementOrder  the order of elements:
-    #         ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC
+    #         SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC
     #  @return an integer value
     #  @ingroup l1_meshinfo
     def NbPrismsOfOrder(self, elementOrder):
@@ -2349,7 +2403,8 @@ class Mesh:
         return self.mesh.GetElementsId()
 
     ## Returns the list of IDs of mesh elements with the given type
-    #  @param elementType  the required type of elements (SMESH.NODE, SMESH.EDGE, SMESH.FACE or SMESH.VOLUME)
+    #  @param elementType  the required type of elements, either of
+    #         (SMESH.NODE, SMESH.EDGE, SMESH.FACE or SMESH.VOLUME)
     #  @return list of integer values
     #  @ingroup l1_meshinfo
     def GetElementsByType(self, elementType):
@@ -2366,18 +2421,21 @@ class Mesh:
 
     ## Returns the type of mesh element
     #  @return the value from SMESH::ElementType enumeration
+    #          Type SMESH.ElementType._items in the Python Console to see all possible values.
     #  @ingroup l1_meshinfo
     def GetElementType(self, id, iselem=True):
         return self.mesh.GetElementType(id, iselem)
 
     ## Returns the geometric type of mesh element
     #  @return the value from SMESH::EntityType enumeration
+    #          Type SMESH.EntityType._items in the Python Console to see all possible values.
     #  @ingroup l1_meshinfo
     def GetElementGeomType(self, id):
         return self.mesh.GetElementGeomType(id)
 
     ## Returns the shape type of mesh element
-    #  @return the value from SMESH::GeometryType enumeration
+    #  @return the value from SMESH::GeometryType enumeration.
+    #          Type SMESH.GeometryType._items in the Python Console to see all possible values.
     #  @ingroup l1_meshinfo
     def GetElementShape(self, id):
         return self.mesh.GetElementShape(id)
@@ -2495,6 +2553,9 @@ class Mesh:
         return self.mesh.IsMediumNode(elementID, nodeID)
 
     ## Returns true if the given node is the medium node in one of quadratic elements
+    #  @param nodeID ID of the node
+    #  @param elementType  the type of elements to check a state of the node, either of
+    #         (SMESH.ALL, SMESH.NODE, SMESH.EDGE, SMESH.FACE or SMESH.VOLUME)
     #  @ingroup l1_meshinfo
     def IsMediumNodeOfAnyElem(self, nodeID, elementType = SMESH.ALL ):
         return self.mesh.IsMediumNodeOfAnyElem(nodeID, elementType)
@@ -2918,8 +2979,9 @@ class Mesh:
     #  @param x  the X coordinate of a point
     #  @param y  the Y coordinate of a point
     #  @param z  the Z coordinate of a point
-    #  @param elementType type of elements to find (SMESH.ALL type
-    #         means elements of any type excluding nodes, discrete and 0D elements)
+    #  @param elementType type of elements to find; either of 
+    #         (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME); SMESH.ALL type
+    #         means elements of any type excluding nodes, discrete and 0D elements.
     #  @param meshPart a part of mesh (group, sub-mesh) to search within
     #  @return list of IDs of found elements
     #  @ingroup l2_modif_throughp
@@ -2929,10 +2991,9 @@ class Mesh:
         else:
             return self.editor.FindElementsByPoint(x, y, z, elementType)
 
-    # Return point state in a closed 2D mesh in terms of TopAbs_State enumeration:
-    # 0-IN, 1-OUT, 2-ON, 3-UNKNOWN
-    # TopAbs_UNKNOWN state means that either mesh is wrong or the analysis fails.
-
+    ## Return point state in a closed 2D mesh in terms of TopAbs_State enumeration:
+    #  0-IN, 1-OUT, 2-ON, 3-UNKNOWN
+    #  UNKNOWN state means that either mesh is wrong or the analysis fails.
     def GetPointState(self, x, y, z):
         return self.editor.GetPointState(x, y, z)
 
@@ -3050,12 +3111,14 @@ class Mesh:
         return self.editor.Reorient2DBy3D( the2DObject, the3DObject, theOutsideNormal )
 
     ## Fuses the neighbouring triangles into quadrangles.
-    #  @param IDsOfElements The triangles to be fused,
-    #  @param theCriterion  is a numerical functor, in terms of enum SMESH.FunctorType, used to
-    #                       choose a neighbour to fuse with.
+    #  @param IDsOfElements The triangles to be fused.
+    #  @param theCriterion  a numerical functor, in terms of enum SMESH.FunctorType, used to
+    #          choose a neighbour to fuse with.
+    #          Type SMESH.FunctorType._items in the Python Console to see all items.
+    #          Note that not all items corresponds to numerical functors.
     #  @param MaxAngle      is the maximum angle between element normals at which the fusion
-    #                       is still performed; theMaxAngle is mesured in radians.
-    #                       Also it could be a name of variable which defines angle in degrees.
+    #          is still performed; theMaxAngle is mesured in radians.
+    #          Also it could be a name of variable which defines angle in degrees.
     #  @return TRUE in case of success, FALSE otherwise.
     #  @ingroup l2_modif_unitetri
     def TriToQuad(self, IDsOfElements, theCriterion, MaxAngle):
@@ -3069,9 +3132,11 @@ class Mesh:
     ## Fuses the neighbouring triangles of the object into quadrangles
     #  @param theObject is mesh, submesh or group
     #  @param theCriterion is a numerical functor, in terms of enum SMESH.FunctorType, used to
-    #         choose a neighbour to fuse with.
+    #          choose a neighbour to fuse with.
+    #          Type SMESH.FunctorType._items in the Python Console to see all items.
+    #          Note that not all items corresponds to numerical functors.
     #  @param MaxAngle   a max angle between element normals at which the fusion
-    #                   is still performed; theMaxAngle is mesured in radians.
+    #          is still performed; theMaxAngle is mesured in radians.
     #  @return TRUE in case of success, FALSE otherwise.
     #  @ingroup l2_modif_unitetri
     def TriToQuadObject (self, theObject, theCriterion, MaxAngle):
@@ -3087,6 +3152,8 @@ class Mesh:
     #  @param theCriterion   is a numerical functor, in terms of enum SMESH.FunctorType, used to
     #         choose a diagonal for splitting. If @a theCriterion is None, which is a default
     #         value, then quadrangles will be split by the smallest diagonal.
+    #         Type SMESH.FunctorType._items in the Python Console to see all items.
+    #         Note that not all items corresponds to numerical functors.
     #  @return TRUE in case of success, FALSE otherwise.
     #  @ingroup l2_modif_cutquadr
     def QuadToTri (self, IDsOfElements, theCriterion = None):
@@ -3103,6 +3170,8 @@ class Mesh:
     #  @param theCriterion is a numerical functor, in terms of enum SMESH.FunctorType, used to
     #         choose a diagonal for splitting. If @a theCriterion is None, which is a default
     #         value, then quadrangles will be split by the smallest diagonal.
+    #         Type SMESH.FunctorType._items in the Python Console to see all items.
+    #         Note that not all items corresponds to numerical functors.
     #  @return TRUE in case of success, FALSE otherwise.
     #  @ingroup l2_modif_cutquadr
     def QuadToTriObject (self, theObject, theCriterion = None):
@@ -3154,6 +3223,8 @@ class Mesh:
     #  @param IDOfQuad   the ID of the quadrangle to be splitted.
     #  @param theCriterion  is a numerical functor, in terms of enum SMESH.FunctorType, used to
     #         choose a diagonal for splitting.
+    #         Type SMESH.FunctorType._items in the Python Console to see all items.
+    #         Note that not all items corresponds to numerical functors.
     #  @return 1 if 1-3 diagonal is better, 2 if 2-4
     #          diagonal is better, 0 if error occurs.
     #  @ingroup l2_modif_cutquadr
@@ -3174,6 +3245,29 @@ class Mesh:
             elems = self.editor.MakeIDSource(elems, SMESH.VOLUME)
             unRegister.set( elems )
         self.editor.SplitVolumesIntoTetra(elems, method)
+        return
+
+    ## Split bi-quadratic elements into linear ones without creation of additional nodes:
+    #   - bi-quadratic triangle will be split into 3 linear quadrangles;
+    #   - bi-quadratic quadrangle will be split into 4 linear quadrangles;
+    #   - tri-quadratic hexahedron will be split into 8 linear hexahedra.
+    #   Quadratic elements of lower dimension  adjacent to the split bi-quadratic element
+    #   will be split in order to keep the mesh conformal.
+    #  @param elems - elements to split: sub-meshes, groups, filters or element IDs;
+    #         if None (default), all bi-quadratic elements will be split
+    #  @ingroup l2_modif_cutquadr
+    def SplitBiQuadraticIntoLinear(self, elems=None):
+        unRegister = genObjUnRegister()
+        if elems and isinstance( elems, list ) and isinstance( elems[0], int ):
+            elems = self.editor.MakeIDSource(elems, SMESH.ALL)
+            unRegister.set( elems )
+        if elems is None:
+            elems = [ self.GetMesh() ]
+        if isinstance( elems, Mesh ):
+            elems = [ elems.GetMesh() ]
+        if not isinstance( elems, list ):
+            elems = [elems]
+        self.editor.SplitBiQuadraticIntoLinear( elems )
 
     ## Splits hexahedra into prisms
     #  @param elems either a list of elements or a mesh or a group or a submesh or a filter
@@ -3473,8 +3567,8 @@ class Mesh:
     #  @param elements - elements whose boundary is to be checked:
     #                    mesh, group, sub-mesh or list of elements
     #   if elements is mesh, it must be the mesh whose MakeBoundaryMesh() is called
-    #  @param dimension - defines type of boundary elements to create:
-    #                     SMESH.BND_2DFROM3D, SMESH.BND_1DFROM3D, SMESH.BND_1DFROM2D
+    #  @param dimension - defines type of boundary elements to create, either of
+    #                     { SMESH.BND_2DFROM3D, SMESH.BND_1DFROM3D, SMESH.BND_1DFROM2D }
     #    SMESH.BND_1DFROM3D creates mesh edges on all borders of free facets of 3D cells
     #  @param groupName - a name of group to store created boundary elements in,
     #                     "" means not to create the group
@@ -3504,7 +3598,8 @@ class Mesh:
     ##
     # @brief Creates missing boundary elements around either the whole mesh or 
     #    groups of elements
-    #  @param dimension - defines type of boundary elements to create
+    #  @param dimension - defines type of boundary elements to create, either of
+    #                     { SMESH.BND_2DFROM3D, SMESH.BND_1DFROM3D, SMESH.BND_1DFROM2D }
     #  @param groupName - a name of group to store all boundary elements in,
     #    "" means not to create the group
     #  @param meshName - a name of a new mesh, which is a copy of the initial 
index ea8fdc9..5348607 100644 (file)
@@ -134,13 +134,14 @@ namespace
    */
   struct SinuousFace
   {
-    FaceQuadStruct::Ptr   _quad;
-    vector< TopoDS_Edge > _edges;
-    vector< TopoDS_Edge > _sinuSide[2], _shortSide[2];
-    vector< TopoDS_Edge > _sinuEdges;
-    int                   _nbWires;
-    list< int >           _nbEdgesInWire;
-    TMergeMap             _nodesToMerge;
+    FaceQuadStruct::Ptr          _quad;
+    vector< TopoDS_Edge >        _edges;
+    vector< TopoDS_Edge >        _sinuSide[2], _shortSide[2];
+    vector< TopoDS_Edge >        _sinuEdges;
+    vector< Handle(Geom_Curve) > _sinuCurves;
+    int                          _nbWires;
+    list< int >                  _nbEdgesInWire;
+    TMergeMap                    _nodesToMerge;
 
     SinuousFace( const TopoDS_Face& f ): _quad( new FaceQuadStruct )
     {
@@ -830,11 +831,11 @@ namespace
    */
   //================================================================================
 
-  bool findVertex( NodePoint&                  theNodePnt,
-                   const vector<TopoDS_Edge>&  theSinuEdges,
-                   size_t                      theEdgeIndPrev,
-                   size_t                      theEdgeIndNext,
-                   SMESHDS_Mesh*               theMeshDS)
+  bool findVertexAndNode( NodePoint&                  theNodePnt,
+                          const vector<TopoDS_Edge>&  theSinuEdges,
+                          SMESHDS_Mesh*               theMeshDS = 0,
+                          size_t                      theEdgeIndPrev = 0,
+                          size_t                      theEdgeIndNext = 0)
   {
     if ( theNodePnt._edgeInd >= theSinuEdges.size() )
       return false;
@@ -851,7 +852,7 @@ namespace
     else if ( theEdgeIndPrev != theEdgeIndNext )
       TopExp::CommonVertex( theSinuEdges[theEdgeIndPrev], theSinuEdges[theEdgeIndNext], V );
 
-    if ( !V.IsNull() )
+    if ( !V.IsNull() && theMeshDS )
     {
       theNodePnt._node = SMESH_Algo::VertexNode( V, theMeshDS );
       if ( !theNodePnt._node )
@@ -860,9 +861,8 @@ namespace
         theNodePnt._node = theMeshDS->AddNode( p.X(), p.Y(), p.Z() );
         theMeshDS->SetNodeOnVertex( theNodePnt._node, V );
       }
-      return true;
     }
-    return false;
+    return !V.IsNull();
   }
 
   //================================================================================
@@ -881,41 +881,44 @@ namespace
   //================================================================================
 
   bool projectVertices( SMESH_MesherHelper&                           theHelper,
-                        //const double                                  theMinSegLen,
                         const SMESH_MAT2d::MedialAxis&                theMA,
                         const vector< SMESH_MAT2d::BranchPoint >&     theDivPoints,
                         const vector< std::size_t > &                 theEdgeIDs1,
                         const vector< std::size_t > &                 theEdgeIDs2,
-                        const vector<TopoDS_Edge>&                    theSinuEdges,
-                        const vector< Handle(Geom_Curve) >&           theCurves,
                         const vector< bool >&                         theIsEdgeComputed,
                         map< double, pair< NodePoint, NodePoint > > & thePointsOnE,
-                        TMergeMap&                                    theNodes2Merge)
+                        SinuousFace&                                  theSinuFace)
   {
-    if ( theDivPoints.empty() )
-      return true;
-
     SMESHDS_Mesh* meshDS = theHelper.GetMeshDS();
+    const vector<TopoDS_Edge>&       theSinuEdges = theSinuFace._sinuEdges;
+    const vector< Handle(Geom_Curve) >& theCurves = theSinuFace._sinuCurves;
 
     double uMA;
     SMESH_MAT2d::BoundaryPoint bp[2];
     const SMESH_MAT2d::Branch& branch = *theMA.getBranch(0);
 
-    // fill a map holding NodePoint's of ends of theSinuEdges
-    map< double, pair< NodePoint, NodePoint > > extremaNP;
-    map< double, pair< NodePoint, NodePoint > >::iterator u2NP0, u2NP1;
+    // add to thePointsOnE NodePoint's of ends of theSinuEdges
     if ( !branch.getBoundaryPoints( 0., bp[0], bp[1] ) ||
          !theMA.getBoundary().moveToClosestEdgeEnd( bp[0] ) ||
          !theMA.getBoundary().moveToClosestEdgeEnd( bp[1] )) return false;
-    u2NP0 = extremaNP.insert
-      ( make_pair( 0., make_pair( NodePoint( bp[0]), NodePoint( bp[1])))).first;
+    NodePoint np0( bp[0]), np1( bp[1] );
+    findVertexAndNode( np0, theSinuEdges, meshDS );
+    findVertexAndNode( np1, theSinuEdges, meshDS );
+    thePointsOnE.insert( make_pair( -0.1, make_pair( np0, np1 )));
+
     if ( !branch.getBoundaryPoints( 1., bp[0], bp[1] ) ||
          !theMA.getBoundary().moveToClosestEdgeEnd( bp[0] ) ||
          !theMA.getBoundary().moveToClosestEdgeEnd( bp[1] )) return false;
-    u2NP1 = extremaNP.insert
-      ( make_pair( 1., make_pair( NodePoint( bp[0]), NodePoint( bp[1])))).first;
+    np0 = bp[0]; np1 = bp[1];
+    findVertexAndNode( np0, theSinuEdges, meshDS );
+    findVertexAndNode( np1, theSinuEdges, meshDS );
+    thePointsOnE.insert( make_pair( 1.1, make_pair( np0, np1)));
 
     // project theDivPoints
+
+    if ( theDivPoints.empty() )
+      return true;
+
     for ( size_t i = 0; i < theDivPoints.size(); ++i )
     {
       if ( !branch.getParameter( theDivPoints[i], uMA ))
@@ -928,8 +931,8 @@ namespace
         NodePoint( bp[1] )
       };
       bool isVertex[2] = {
-        findVertex( np[0], theSinuEdges, theEdgeIDs1[i], theEdgeIDs1[i+1], meshDS ),
-        findVertex( np[1], theSinuEdges, theEdgeIDs2[i], theEdgeIDs2[i+1], meshDS )
+        findVertexAndNode( np[0], theSinuEdges, meshDS, theEdgeIDs1[i], theEdgeIDs1[i+1] ),
+        findVertexAndNode( np[1], theSinuEdges, meshDS, theEdgeIDs2[i], theEdgeIDs2[i+1] )
       };
 
       map< double, pair< NodePoint, NodePoint > >::iterator u2NP =
@@ -957,10 +960,10 @@ namespace
       bool isShortPrev[2], isShortNext[2];
       map< double, pair< NodePoint, NodePoint > >::iterator u2NPPrev = u2NP, u2NPNext = u2NP;
       --u2NPPrev; ++u2NPNext;
-      bool hasPrev = ( u2NP     != thePointsOnE.begin() );
-      bool hasNext = ( u2NPNext != thePointsOnE.end() );
-      if ( !hasPrev ) u2NPPrev = u2NP0;
-      if ( !hasNext ) u2NPNext = u2NP1;
+      // bool hasPrev = ( u2NP     != thePointsOnE.begin() );
+      // bool hasNext = ( u2NPNext != thePointsOnE.end() );
+      // if ( !hasPrev ) u2NPPrev = u2NP0;
+      // if ( !hasNext ) u2NPNext = u2NP1;
       for ( int iS = 0; iS < 2; ++iS ) // side with Vertex and side with Nodes
       {
         NodePoint np     = get( u2NP->second,     iS );
@@ -1003,14 +1006,16 @@ namespace
         u2NPClose = isShortPrev[ iNode ] ? u2NPPrev : u2NPNext;
         NodePoint& npProj   = get( u2NP->second,      iNode ); // NP of VERTEX projection
         NodePoint& npCloseN = get( u2NPClose->second, iNode ); // NP close to npProj
-        // npProj._edgeInd = npCloseN._edgeInd;
+        npProj = npCloseN;
+        npProj._node = 0;
+        //npProj._edgeInd = npCloseN._edgeInd;
         // npProj._u       = npCloseN._u + 1e-3 * Abs( get( u2NPPrev->second, iNode )._u -
         //                                             get( u2NPNext->second, iNode )._u );
-        gp_Pnt        p = npProj.Point( theCurves );
-        npProj._node    = meshDS->AddNode( p.X(), p.Y(), p.Z() );
-        meshDS->SetNodeOnEdge( npProj._node, theSinuEdges[ npProj._edgeInd ], npProj._u  );
+        // gp_Pnt        p = npProj.Point( theCurves );
+        // npProj._node    = meshDS->AddNode( p.X(), p.Y(), p.Z() );
+        // meshDS->SetNodeOnEdge( npProj._node, theSinuEdges[ npProj._edgeInd ], npProj._u  );
 
-        theNodes2Merge[ npCloseN._node ].push_back( npProj._node );
+        //theNodes2Merge[ npCloseN._node ].push_back( npProj._node );
       }
     }
     return true;
@@ -1018,6 +1023,119 @@ namespace
 
   //================================================================================
   /*!
+   * \brief Move coincident nodes to make node params on EDGE unique
+   *  \param [in] theHelper - the helper
+   *  \param [in] thePointsOnE - nodes on two opposite river sides
+   *  \param [in] theSinuFace - the sinuous FACE
+   *  \param [out] theNodes2Merge - the map of nodes to merge
+   */
+  //================================================================================
+
+  void separateNodes( SMESH_MesherHelper&                           theHelper,
+                      map< double, pair< NodePoint, NodePoint > > & thePointsOnE,
+                      SinuousFace&                                  theSinuFace )
+  {
+    if ( thePointsOnE.size() < 2 )
+      return;
+
+    SMESHDS_Mesh* meshDS = theHelper.GetMeshDS();
+    const vector<TopoDS_Edge>& theSinuEdges = theSinuFace._sinuEdges;
+
+    typedef map< double, pair< NodePoint, NodePoint > >::iterator TIterator;
+
+    for ( int iSide = 0; iSide < 2; ++iSide )
+    {
+      TIterator u2NP0, u2NP1, u2NP = thePointsOnE.begin();
+      while ( u2NP != thePointsOnE.end() )
+      {
+        while ( u2NP != thePointsOnE.end() &&
+                get( u2NP->second, iSide )._node )
+          ++u2NP; // skip NP with an existing node (VERTEXes must be meshed)
+        if ( u2NP == thePointsOnE.end() )
+          break;
+
+        // find a range of not meshed NP on one EDGE
+        u2NP0 = u2NP;
+        if ( !findVertexAndNode( get( u2NP0->second, iSide ), theSinuEdges ))
+          --u2NP0;
+        int iCurEdge = get( u2NP->second, iSide )._edgeInd;
+        int nbNP = 1;
+        while ( get( u2NP->second, iSide )._edgeInd == iCurEdge &&
+                get( u2NP->second, iSide )._node == 0 )
+          ++u2NP, ++nbNP;
+        u2NP1 = u2NP; // end of not meshed NP on iCurEdge
+
+        // fix parameters of extremity NP of the range
+        NodePoint* np0 = & get( u2NP0->second, iSide );
+        NodePoint* np1 = & get( u2NP1->second, iSide );
+        const TopoDS_Edge& edge = TopoDS::Edge( theSinuFace._sinuEdges[ iCurEdge ]);
+        if ( np0->_node && np0->_edgeInd != iCurEdge )
+        {
+          np0->_u       = theHelper.GetNodeU( edge, np0->_node );
+          np0->_edgeInd = iCurEdge;
+        }
+        if ( np1->_node && np1->_edgeInd != iCurEdge )
+        {
+          np1->_u       = theHelper.GetNodeU( edge, np1->_node );
+          np1->_edgeInd = iCurEdge;
+        }
+
+        // find coincident NPs
+        double f,l;
+        BRep_Tool::Range( edge, f,l );
+        double tol = 1e-2* (l-f) / nbNP;
+        TIterator u2NPEq = thePointsOnE.end();
+        u2NP = u2NP0;
+        for ( ++u2NP; u2NP0 != u2NP1; ++u2NP, ++u2NP0 )
+        {
+          np0 = & get( u2NP0->second, iSide );
+          np1 = & get( u2NP->second,  iSide );
+          bool coincides = ( Abs( np0->_u - np1->_u ) < tol );
+          if ( coincides && u2NPEq == thePointsOnE.end() )
+            u2NPEq = u2NP0;
+
+          if (( u2NPEq != thePointsOnE.end() ) &&
+              ( u2NP == u2NP1 || !coincides ))
+          {
+            if ( !get( u2NPEq->second, iSide )._node )
+              --u2NPEq;
+            if ( coincides && !get( u2NP->second, iSide )._node && u2NP0 != u2NP1 )
+              ++u2NP;
+
+            // distribute nodes between u2NPEq and u2NP
+            size_t nbSeg = std::distance( u2NPEq, u2NP );
+            double    du = 1. / nbSeg * ( get( u2NP->second,   iSide )._u -
+                                          get( u2NPEq->second, iSide )._u );
+            double     u = get( u2NPEq->second, iSide )._u + du;
+
+            const SMDS_MeshNode* closeNode =
+              get(( coincides ? u2NP : u2NPEq )->second, iSide )._node;
+            list< const SMDS_MeshNode* >& eqNodes = theSinuFace._nodesToMerge[ closeNode ];
+
+            for ( ++u2NPEq; u2NPEq != u2NP; ++u2NPEq, u += du )
+            {
+              np0       = & get( u2NPEq->second, iSide );
+              np0->_u   = u;
+              gp_Pnt p  = np0->Point( theSinuFace._sinuCurves );
+              np0->_node = meshDS->AddNode( p.X(), p.Y(), p.Z() );
+              meshDS->SetNodeOnEdge( np0->_node, theSinuEdges[ np0->_edgeInd ], np0->_u  );
+              if ( !closeNode )
+                eqNodes = theSinuFace._nodesToMerge[ closeNode = np0->_node ];
+              else
+                eqNodes.push_back( np0->_node );
+            }
+          }
+        }
+        u2NP = u2NP1;
+        while ( get( u2NP->second, iSide )._edgeInd != iCurEdge )
+          --u2NP;
+        u2NP++;
+      }
+    }
+  }
+
+  //================================================================================
+  /*!
    * \brief Divide the sinuous EDGEs by projecting the division point of Medial
    *        Axis to the EGDEs
    *  \param [in] theHelper - the helper
@@ -1048,11 +1166,12 @@ namespace
     SMESHDS_Mesh* meshDS = theHelper.GetMeshDS();
     double f,l;
 
+    // get data of sinuous EDGEs and remove unnecessary nodes
     const vector< TopoDS_Edge >& theSinuEdges = theSinuFace._sinuEdges;
-    vector< Handle(Geom_Curve) > curves ( theSinuEdges.size() );
+    vector< Handle(Geom_Curve) >& curves      = theSinuFace._sinuCurves;
     vector< int >                edgeIDs( theSinuEdges.size() );
     vector< bool >            isComputed( theSinuEdges.size() );
-    //bool hasComputed = false;
+    curves.resize( theSinuEdges.size(), 0 );
     for ( size_t i = 0; i < theSinuEdges.size(); ++i )
     {
       curves[i] = BRep_Tool::Curve( theSinuEdges[i], f,l );
@@ -1172,10 +1291,12 @@ namespace
       ++iEdgePair;
     }
 
-    if ( !projectVertices( theHelper, theMA, divPoints, edgeIDs1, edgeIDs2, theSinuEdges,
-                           curves, isComputed, pointsOnE, theSinuFace._nodesToMerge ))
+    if ( !projectVertices( theHelper, theMA, divPoints, edgeIDs1, edgeIDs2,
+                           isComputed, pointsOnE, theSinuFace ))
       return false;
 
+    separateNodes( theHelper, pointsOnE, theSinuFace );
+
     // create nodes
     TMAPar2NPoints::iterator u2np = pointsOnE.begin();
     for ( ; u2np != pointsOnE.end(); ++u2np )
@@ -1353,6 +1474,7 @@ namespace
     TMergeMap::iterator n2nn = theSinuFace._nodesToMerge.begin();
     for ( ; n2nn != theSinuFace._nodesToMerge.end(); ++n2nn )
     {
+      if ( !n2nn->first ) continue;
       nodesGroups.push_back( list< const SMDS_MeshNode* >() );
       list< const SMDS_MeshNode* > & group = nodesGroups.back();