Salome HOME
23080: [CEA 1497] Do not merge a middle node in quadratic with the extreme nodes...
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
index 324b6b81dabf7a55c2d5b9085717e9d949de8ae6..fc945c44e3e90e8a5bce67855dba29f326248466 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
+// 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
@@ -6,7 +6,7 @@
 // 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.
+// 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
@@ -42,6 +42,7 @@
 #include "SMESH_Algo.hxx"
 #include "SMESH_ControlsDef.hxx"
 #include "SMESH_Group.hxx"
+#include "SMESH_MeshAlgos.hxx"
 #include "SMESH_MesherHelper.hxx"
 #include "SMESH_OctreeNode.hxx"
 #include "SMESH_subMesh.hxx"
@@ -49,6 +50,7 @@
 #include <Basics_OCCTVersion.hxx>
 
 #include "utilities.h"
+#include "chrono.hxx"
 
 #include <BRepAdaptor_Surface.hxx>
 #include <BRepBuilderAPI_MakeEdge.hxx>
 #include <Extrema_GenExtPS.hxx>
 #include <Extrema_POnCurv.hxx>
 #include <Extrema_POnSurf.hxx>
-#include <GC_MakeSegment.hxx>
 #include <Geom2d_Curve.hxx>
-#include <GeomAPI_ExtremaCurveCurve.hxx>
 #include <GeomAdaptor_Surface.hxx>
 #include <Geom_Curve.hxx>
-#include <Geom_Line.hxx>
 #include <Geom_Surface.hxx>
-#include <IntAna_IntConicQuad.hxx>
-#include <IntAna_Quadric.hxx>
 #include <Precision.hxx>
 #include <TColStd_ListOfInteger.hxx>
 #include <TopAbs_State.hxx>
@@ -97,6 +94,8 @@
 #include <algorithm>
 #include <sstream>
 
+#include <boost/tuple/tuple.hpp>
+
 #include <Standard_Failure.hxx>
 #include <Standard_ErrorHandler.hxx>
 
 using namespace std;
 using namespace SMESH::Controls;
 
-typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
-typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
-
-typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
+namespace
+{
+  template < class ELEM_SET >
+  SMDS_ElemIteratorPtr elemSetIterator( const ELEM_SET& elements )
+  {
+    typedef SMDS_SetIterator
+      < SMDS_pElement, typename ELEM_SET::const_iterator> TSetIterator;
+    return SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
+  }
+}
 
 //=======================================================================
 //function : SMESH_MeshEditor
@@ -120,6 +125,53 @@ SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
 {
 }
 
+//================================================================================
+/*!
+ * \brief Clears myLastCreatedNodes and myLastCreatedElems
+ */
+//================================================================================
+
+void SMESH_MeshEditor::ClearLastCreated()
+{
+  myLastCreatedNodes.Clear();
+  myLastCreatedElems.Clear();
+}
+
+//================================================================================
+/*!
+ * \brief Initializes members by an existing element
+ *  \param [in] elem - the source element
+ *  \param [in] basicOnly - if true, does not set additional data of Ball and Polyhedron
+ */
+//================================================================================
+
+SMESH_MeshEditor::ElemFeatures&
+SMESH_MeshEditor::ElemFeatures::Init( const SMDS_MeshElement* elem, bool basicOnly )
+{
+  if ( elem )
+  {
+    myType = elem->GetType();
+    if ( myType == SMDSAbs_Face || myType == SMDSAbs_Volume )
+    {
+      myIsPoly = elem->IsPoly();
+      if ( myIsPoly )
+      {
+        myIsQuad = elem->IsQuadratic();
+        if ( myType == SMDSAbs_Volume && !basicOnly )
+        {
+          vector<int > quant = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
+          myPolyhedQuantities.swap( quant );
+        }
+      }
+    }
+    else if ( myType == SMDSAbs_Ball && !basicOnly )
+    {
+      myBallDiameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
+    }
+  }
+  return *this;
+}
+
 //=======================================================================
 /*!
  * \brief Add element
@@ -128,18 +180,16 @@ SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
 
 SMDS_MeshElement*
 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
-                             const SMDSAbs_ElementType            type,
-                             const bool                           isPoly,
-                             const int                            ID,
-                             const double                         ballDiameter)
+                             const ElemFeatures&                  features)
 {
-  //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
   SMDS_MeshElement* e = 0;
   int nbnode = node.size();
   SMESHDS_Mesh* mesh = GetMeshDS();
-  switch ( type ) {
+  const int ID = features.myID;
+
+  switch ( features.myType ) {
   case SMDSAbs_Face:
-    if ( !isPoly ) {
+    if ( !features.myIsPoly ) {
       if      (nbnode == 3) {
         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
         else           e = mesh->AddFace      (node[0], node[1], node[2] );
@@ -154,6 +204,12 @@ SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
                                                node[4], node[5] );
       }
+      else if (nbnode == 7) {
+        if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
+                                               node[4], node[5], node[6], ID);
+        else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
+                                               node[4], node[5], node[6] );
+      }
       else if (nbnode == 8) {
         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
                                                node[4], node[5], node[6], node[7], ID);
@@ -166,14 +222,21 @@ SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
                                                node[4], node[5], node[6], node[7], node[8] );
       }
-    } else {
+    }
+    else if ( !features.myIsQuad )
+    {
       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
       else           e = mesh->AddPolygonalFace      (node    );
     }
+    else if ( nbnode % 2 == 0 ) // just a protection
+    {
+      if ( ID >= 1 ) e = mesh->AddQuadPolygonalFaceWithID(node, ID);
+      else           e = mesh->AddQuadPolygonalFace      (node    );
+    }
     break;
 
   case SMDSAbs_Volume:
-    if ( !isPoly ) {
+    if ( !features.myIsPoly ) {
       if      (nbnode == 4) {
         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
@@ -261,6 +324,16 @@ SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
                                                  node[24],node[25],node[26] );
       }
     }
+    else if ( !features.myIsQuad )
+    {
+      if ( ID >= 1 ) e = mesh->AddPolyhedralVolumeWithID(node, features.myPolyhedQuantities, ID);
+      else           e = mesh->AddPolyhedralVolume      (node, features.myPolyhedQuantities    );
+    }
+    else
+    {
+      // if ( ID >= 1 ) e = mesh->AddQuadPolyhedralVolumeWithID(node, features.myPolyhedQuantities,ID);
+      // else           e = mesh->AddQuadPolyhedralVolume      (node, features.myPolyhedQuantities   );
+    }
     break;
 
   case SMDSAbs_Edge:
@@ -283,12 +356,12 @@ SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
 
   case SMDSAbs_Node:
     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
-    else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
+    else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z()    );
     break;
 
   case SMDSAbs_Ball:
-    if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], ballDiameter, ID);
-    else           e = mesh->AddBall      (node[0], ballDiameter);
+    if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], features.myBallDiameter, ID);
+    else           e = mesh->AddBall      (node[0], features.myBallDiameter    );
     break;
 
   default:;
@@ -303,10 +376,8 @@ SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
  */
 //=======================================================================
 
-SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
-                                               const SMDSAbs_ElementType type,
-                                               const bool                isPoly,
-                                               const int                 ID)
+SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
+                                               const ElemFeatures& features)
 {
   vector<const SMDS_MeshNode*> nodes;
   nodes.reserve( nodeIDs.size() );
@@ -317,7 +388,7 @@ SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs
     else
       return 0;
   }
-  return AddElement( nodes, type, isPoly, ID );
+  return AddElement( nodes, features );
 }
 
 //=======================================================================
@@ -389,6 +460,53 @@ int SMESH_MeshEditor::Remove (const list< int >& theIDs,
   return removed;
 }
 
+//================================================================================
+/*!
+ * \brief Create 0D elements on all nodes of the given object except those
+ *        nodes on which a 0D element already exists.
+ *  \param elements - Elements on whose nodes to create 0D elements; if empty, 
+ *                    the all mesh is treated
+ *  \param all0DElems - returns all 0D elements found or created on nodes of \a elements
+ */
+//================================================================================
+
+void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements,
+                                                   TIDSortedElemSet&       all0DElems )
+{
+  SMDS_ElemIteratorPtr elemIt;
+  vector< const SMDS_MeshElement* > allNodes;
+  if ( elements.empty() )
+  {
+    allNodes.reserve( GetMeshDS()->NbNodes() );
+    elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node );
+    while ( elemIt->more() )
+      allNodes.push_back( elemIt->next() );
+
+    elemIt = elemSetIterator( allNodes );
+  }
+  else
+  {
+    elemIt = elemSetIterator( elements );
+  }
+
+  while ( elemIt->more() )
+  {
+    const SMDS_MeshElement* e = elemIt->next();
+    SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
+    while ( nodeIt->more() )
+    {
+      const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
+      SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement );
+      if ( it0D->more() )
+        all0DElems.insert( it0D->next() );
+      else {
+        myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n ));
+        all0DElems.insert( myLastCreatedElems.Last() );
+      }
+    }
+  }
+}
+
 //=======================================================================
 //function : FindShape
 //purpose  : Return an index of the shape theElem is on
@@ -448,14 +566,12 @@ int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
   }
   else
   {
-    const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
-    map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
-    for ( ; id_sm != id2sm.end(); ++id_sm )
-      if ( id_sm->second->Contains( theElem ))
-        return id_sm->first;
+    SMESHDS_SubMeshIteratorPtr smIt = GetMeshDS()->SubMeshes();
+    while ( const SMESHDS_SubMesh* sm = smIt->next() )
+      if ( sm->Contains( theElem ))
+        return sm->GetID();
   }
 
-  //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
   return 0;
 }
 
@@ -477,12 +593,12 @@ bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
 }
 
 //=======================================================================
-//function : ShiftNodesQuadTria
-//purpose  : auxilary
-//           Shift nodes in the array corresponded to quadratic triangle
+//function : shiftNodesQuadTria
+//purpose  : Shift nodes in the array corresponded to quadratic triangle
 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
 //=======================================================================
-static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
+
+static void shiftNodesQuadTria(vector< const SMDS_MeshNode* >& aNodes)
 {
   const SMDS_MeshNode* nd1 = aNodes[0];
   aNodes[0] = aNodes[1];
@@ -495,53 +611,42 @@ static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
 }
 
 //=======================================================================
-//function : edgeConnectivity
-//purpose  : auxilary 
-//           return number of the edges connected with the theNode.
+//function : nbEdgeConnectivity
+//purpose  : return number of the edges connected with the theNode.
 //           if theEdges has connections with the other type of the
-//           elements, return -1 
+//           elements, return -1
 //=======================================================================
+
 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
 {
-  SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
-  int nb=0;
-  while(elemIt->more()) {
-    elemIt->next();
-    nb++;
-  }
-  return nb;
+  // SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
+  // int nb=0;
+  // while(elemIt->more()) {
+  //   elemIt->next();
+  //   nb++;
+  // }
+  // return nb;
+  return theNode->NbInverseElements();
 }
 
-
 //=======================================================================
-//function : GetNodesFromTwoTria
-//purpose  : auxilary
-//           Shift nodes in the array corresponded to quadratic triangle
-//           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
+//function : getNodesFromTwoTria
+//purpose  : 
 //=======================================================================
-static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
+
+static bool getNodesFromTwoTria(const SMDS_MeshElement * theTria1,
                                 const SMDS_MeshElement * theTria2,
-                                const SMDS_MeshNode* N1[],
-                                const SMDS_MeshNode* N2[])
+                                vector< const SMDS_MeshNode*>& N1,
+                                vector< const SMDS_MeshNode*>& N2)
 {
-  SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
-  int i=0;
-  while(i<6) {
-    N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
-    i++;
-  }
-  if(it->more()) return false;
-  it = theTria2->nodesIterator();
-  i=0;
-  while(i<6) {
-    N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
-    i++;
-  }
-  if(it->more()) return false;
+  N1.assign( theTria1->begin_nodes(), theTria1->end_nodes() );
+  if ( N1.size() < 6 ) return false;
+  N2.assign( theTria2->begin_nodes(), theTria2->end_nodes() );
+  if ( N2.size() < 6 ) return false;
 
   int sames[3] = {-1,-1,-1};
   int nbsames = 0;
-  int j;
+  int i, j;
   for(i=0; i<3; i++) {
     for(j=0; j<3; j++) {
       if(N1[i]==N2[j]) {
@@ -553,18 +658,18 @@ static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
   }
   if(nbsames!=2) return false;
   if(sames[0]>-1) {
-    ShiftNodesQuadTria(N1);
+    shiftNodesQuadTria(N1);
     if(sames[1]>-1) {
-      ShiftNodesQuadTria(N1);
+      shiftNodesQuadTria(N1);
     }
   }
   i = sames[0] + sames[1] + sames[2];
   for(; i<2; i++) {
-    ShiftNodesQuadTria(N2);
+    shiftNodesQuadTria(N2);
   }
-  // now we receive following N1 and N2 (using numeration as above image)
+  // now we receive following N1 and N2 (using numeration as in the image below)
   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
-  // i.e. first nodes from both arrays determ new diagonal
+  // i.e. first nodes from both arrays form a new diagonal
   return true;
 }
 
@@ -599,7 +704,7 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
 
     // put nodes in array and find out indices of the same ones
     const SMDS_MeshNode* aNodes [6];
-    int sameInd [] = { 0, 0, 0, 0, 0, 0 };
+    int sameInd [] = { -1, -1, -1, -1, -1, -1 };
     int i = 0;
     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
     while ( it->more() ) {
@@ -625,15 +730,15 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
     }
 
     // find indices of 1,2 and of A,B in theTria1
-    int iA = 0, iB = 0, i1 = 0, i2 = 0;
+    int iA = -1, iB = 0, i1 = 0, i2 = 0;
     for ( i = 0; i < 6; i++ ) {
-      if ( sameInd [ i ] == 0 ) {
+      if ( sameInd [ i ] == -1 ) {
         if ( i < 3 ) i1 = i;
         else         i2 = i;
       }
       else if (i < 3) {
-        if ( iA ) iB = i;
-        else      iA = i;
+        if ( iA >= 0) iB = i;
+        else          iA = i;
       }
     }
     // nodes 1 and 2 should not be the same
@@ -653,9 +758,11 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
   } // end if(F1 && F2)
 
   // check case of quadratic faces
-  if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
+  if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle &&
+      theTria1->GetEntityType() != SMDSEntity_BiQuad_Triangle)
     return false;
-  if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
+  if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle&&
+      theTria2->GetEntityType() != SMDSEntity_BiQuad_Triangle)
     return false;
 
   //       5
@@ -668,32 +775,61 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
   //  4 +--+--+ 3
   //       8
 
-  const SMDS_MeshNode* N1 [6];
-  const SMDS_MeshNode* N2 [6];
-  if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
+  vector< const SMDS_MeshNode* > N1;
+  vector< const SMDS_MeshNode* > N2;
+  if(!getNodesFromTwoTria(theTria1,theTria2,N1,N2))
     return false;
   // now we receive following N1 and N2 (using numeration as above image)
   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
   // i.e. first nodes from both arrays determ new diagonal
 
-  const SMDS_MeshNode* N1new [6];
-  const SMDS_MeshNode* N2new [6];
-  N1new[0] = N1[0];
-  N1new[1] = N2[0];
-  N1new[2] = N2[1];
-  N1new[3] = N1[4];
-  N1new[4] = N2[3];
-  N1new[5] = N1[5];
-  N2new[0] = N1[0];
-  N2new[1] = N1[1];
-  N2new[2] = N2[0];
-  N2new[3] = N1[3];
-  N2new[4] = N2[5];
-  N2new[5] = N1[4];
-  // replaces nodes in faces
-  GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
-  GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
-
+  vector< const SMDS_MeshNode*> N1new( N1.size() );
+  vector< const SMDS_MeshNode*> N2new( N2.size() );
+  N1new.back() = N1.back(); // central node of biquadratic
+  N2new.back() = N2.back();
+  N1new[0] = N1[0];  N2new[0] = N1[0];
+  N1new[1] = N2[0];  N2new[1] = N1[1];
+  N1new[2] = N2[1];  N2new[2] = N2[0];
+  N1new[3] = N1[4];  N2new[3] = N1[3];
+  N1new[4] = N2[3];  N2new[4] = N2[5];
+  N1new[5] = N1[5];  N2new[5] = N1[4];
+  // change nodes in faces
+  GetMeshDS()->ChangeElementNodes( theTria1, &N1new[0], N1new.size() );
+  GetMeshDS()->ChangeElementNodes( theTria2, &N2new[0], N2new.size() );
+
+  // move the central node of biquadratic triangle
+  SMESH_MesherHelper helper( *GetMesh() );
+  for ( int is2nd = 0; is2nd < 2; ++is2nd )
+  {
+    const SMDS_MeshElement*         tria = is2nd ? theTria2 : theTria1;
+    vector< const SMDS_MeshNode*>& nodes = is2nd ? N2new : N1new;
+    if ( nodes.size() < 7 )
+      continue;
+    helper.SetSubShape( tria->getshapeId() );
+    const TopoDS_Face& F = TopoDS::Face( helper.GetSubShape() );
+    gp_Pnt xyz;
+    if ( F.IsNull() )
+    {
+      xyz = ( SMESH_TNodeXYZ( nodes[3] ) +
+              SMESH_TNodeXYZ( nodes[4] ) +
+              SMESH_TNodeXYZ( nodes[5] )) / 3.;
+    }
+    else
+    {
+      bool checkUV;
+      gp_XY uv = ( helper.GetNodeUV( F, nodes[3], nodes[2], &checkUV ) +
+                   helper.GetNodeUV( F, nodes[4], nodes[0], &checkUV ) +
+                   helper.GetNodeUV( F, nodes[5], nodes[1], &checkUV )) / 3.;
+      TopLoc_Location loc;
+      Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc);
+      xyz = S->Value( uv.X(), uv.Y() );
+      xyz.Transform( loc );
+      if ( nodes[6]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE &&  // set UV
+           nodes[6]->getshapeId() > 0 )
+        GetMeshDS()->SetNodeOnFace( nodes[6], nodes[6]->getshapeId(), uv.X(), uv.Y() );
+    }
+    GetMeshDS()->MoveNode( nodes[6], xyz.X(), xyz.Y(), xyz.Z() );
+  }
   return true;
 }
 
@@ -715,30 +851,28 @@ static bool findTriangles(const SMDS_MeshNode *    theNode1,
   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
   while (it->more()) {
     const SMDS_MeshElement* elem = it->next();
-    if ( elem->NbNodes() == 3 )
+    if ( elem->NbCornerNodes() == 3 )
       emap.insert( elem );
   }
   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
   while (it->more()) {
     const SMDS_MeshElement* elem = it->next();
-    if ( emap.find( elem ) != emap.end() ) {
-      if ( theTria1 ) {
-        // theTria1 must be element with minimum ID
-        if( theTria1->GetID() < elem->GetID() ) {
-          theTria2 = elem;
-        }
-        else {
-          theTria2 = theTria1;
-          theTria1 = elem;
-        }
-        break;
-      }
-      else {
+    if ( emap.count( elem )) {
+      if ( !theTria1 )
+      {
         theTria1 = elem;
       }
+      else  
+      {
+        theTria2 = elem;
+        // theTria1 must be element with minimum ID
+        if ( theTria2->GetID() < theTria1->GetID() )
+          std::swap( theTria2, theTria1 );
+        return true;
+      }
     }
   }
-  return ( theTria1 && theTria2 );
+  return false;
 }
 
 //=======================================================================
@@ -927,9 +1061,9 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
   //  4 +--+--+ 3
   //       8
 
-  const SMDS_MeshNode* N1 [6];
-  const SMDS_MeshNode* N2 [6];
-  if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
+  vector< const SMDS_MeshNode* > N1;
+  vector< const SMDS_MeshNode* > N2;
+  if(!getNodesFromTwoTria(tr1,tr2,N1,N2))
     return false;
   // now we receive following N1 and N2 (using numeration as above image)
   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
@@ -981,82 +1115,49 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
   if ( !it || !it->more() )
     return false;
 
-  switch ( theElem->GetType() ) {
+  const SMDSAbs_ElementType type = theElem->GetType();
+  if ( type < SMDSAbs_Edge || type > SMDSAbs_Volume )
+    return false;
 
-  case SMDSAbs_Edge:
-  case SMDSAbs_Face: {
-    if(!theElem->IsQuadratic()) {
-      int i = theElem->NbNodes();
-      vector<const SMDS_MeshNode*> aNodes( i );
-      while ( it->more() )
-        aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
-      return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
-    }
-    else {
-      // quadratic elements
-      if(theElem->GetType()==SMDSAbs_Edge) {
-        vector<const SMDS_MeshNode*> aNodes(3);
-        aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
-        aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
-        aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
-        return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
-      }
-      else {
-        int nbn = theElem->NbNodes();
-        vector<const SMDS_MeshNode*> aNodes(nbn);
-        aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
-        int i=1;
-        for(; i<nbn/2; i++) {
-          aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
-        }
-        for(i=0; i<nbn/2; i++) {
-          aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
-        }
-        return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
-      }
+  const SMDSAbs_EntityType geomType = theElem->GetEntityType();
+  if ( geomType == SMDSEntity_Polyhedra ) // polyhedron
+  {
+    const SMDS_VtkVolume* aPolyedre =
+      dynamic_cast<const SMDS_VtkVolume*>( theElem );
+    if (!aPolyedre) {
+      MESSAGE("Warning: bad volumic element");
+      return false;
     }
-  }
-  case SMDSAbs_Volume: {
-    if (theElem->IsPoly()) {
-      // TODO reorient vtk polyhedron
-      MESSAGE("reorient vtk polyhedron ?");
-      const SMDS_VtkVolume* aPolyedre =
-        dynamic_cast<const SMDS_VtkVolume*>( theElem );
-      if (!aPolyedre) {
-        MESSAGE("Warning: bad volumic element");
-        return false;
-      }
-
-      int nbFaces = aPolyedre->NbFaces();
-      vector<const SMDS_MeshNode *> poly_nodes;
-      vector<int> quantities (nbFaces);
+    const int nbFaces = aPolyedre->NbFaces();
+    vector<const SMDS_MeshNode *> poly_nodes;
+    vector<int> quantities (nbFaces);
 
-      // reverse each face of the polyedre
-      for (int iface = 1; iface <= nbFaces; iface++) {
-        int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
-        quantities[iface - 1] = nbFaceNodes;
+    // reverse each face of the polyedre
+    for (int iface = 1; iface <= nbFaces; iface++) {
+      int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
+      quantities[iface - 1] = nbFaceNodes;
 
-        for (inode = nbFaceNodes; inode >= 1; inode--) {
-          const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
-          poly_nodes.push_back(curNode);
-        }
+      for (inode = nbFaceNodes; inode >= 1; inode--) {
+        const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
+        poly_nodes.push_back(curNode);
       }
-
-      return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
-
-    }
-    else {
-      SMDS_VolumeTool vTool;
-      if ( !vTool.Set( theElem ))
-        return false;
-      vTool.Inverse();
-      MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
-      return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
     }
+    return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
   }
-  default:;
+  else // other elements
+  {
+    vector<const SMDS_MeshNode*> nodes( theElem->begin_nodes(), theElem->end_nodes() );
+    const std::vector<int>& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType, nodes.size() );
+    if ( interlace.empty() )
+    {
+      std::reverse( nodes.begin(), nodes.end() ); // obsolete, just in case
+    }
+    else
+    {
+      SMDS_MeshCell::applyInterlace( interlace, nodes );
+    }
+    return GetMeshDS()->ChangeElementNodes( theElem, &nodes[0], nodes.size() );
   }
-
   return false;
 }
 
@@ -1065,7 +1166,7 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
  * \brief Reorient faces.
  * \param theFaces - the faces to reorient. If empty the whole mesh is meant
  * \param theDirection - desired direction of normal of \a theFace
- * \param theFace - one of \a theFaces that sould be orientated according to
+ * \param theFace - one of \a theFaces that sould be oriented according to
  *        \a theDirection and whose orientation defines orientation of other faces
  * \return number of reoriented faces.
  */
@@ -1087,13 +1188,13 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
 
   // orient theFace according to theDirection
   gp_XYZ normal;
-  SMESH_Algo::FaceNormal( theFace, normal, /*normalized=*/false );
+  SMESH_MeshAlgos::FaceNormal( theFace, normal, /*normalized=*/false );
   if ( normal * theDirection.XYZ() < 0 )
     nbReori += Reorient( theFace );
 
   // Orient other faces
 
-  set< const SMDS_MeshElement* > startFaces;
+  set< const SMDS_MeshElement* > startFaces, visitedFaces;
   TIDSortedElemSet avoidSet;
   set< SMESH_TLink > checkedLinks;
   pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
@@ -1102,16 +1203,26 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
     theFaces.erase( theFace );
   startFaces.insert( theFace );
 
+  int nodeInd1, nodeInd2;
+  const SMDS_MeshElement*           otherFace;
+  vector< const SMDS_MeshElement* > facesNearLink;
+  vector< std::pair< int, int > >   nodeIndsOfFace;
+
   set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
-  while ( startFace != startFaces.end() )
+  while ( !startFaces.empty() )
   {
+    startFace = startFaces.begin();
     theFace = *startFace;
-    const int nbNodes = theFace->NbCornerNodes();
+    startFaces.erase( startFace );
+    if ( !visitedFaces.insert( theFace ).second )
+      continue;
 
     avoidSet.clear();
     avoidSet.insert(theFace);
 
-    NLink link( theFace->GetNode( 0 ), 0 );
+    NLink link( theFace->GetNode( 0 ), (SMDS_MeshNode *) 0 );
+
+    const int nbNodes = theFace->NbCornerNodes();
     for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
     {
       link.second = theFace->GetNode(( i+1 ) % nbNodes );
@@ -1120,37 +1231,152 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
       {
         // link has already been checked and won't be encountered more
         // if the group (theFaces) is manifold
-        checkedLinks.erase( linkIt_isNew.first );
+        //checkedLinks.erase( linkIt_isNew.first );
       }
       else
       {
-        int nodeInd1, nodeInd2;
-        const SMDS_MeshElement* otherFace = FindFaceInSet( link.first, link.second,
-                                                           theFaces, avoidSet,
-                                                           & nodeInd1, & nodeInd2);
+        facesNearLink.clear();
+        nodeIndsOfFace.clear();
+        while (( otherFace = SMESH_MeshAlgos::FindFaceInSet( link.first, link.second,
+                                                             theFaces, avoidSet,
+                                                             &nodeInd1, &nodeInd2 )))
+          if ( otherFace != theFace)
+          {
+            facesNearLink.push_back( otherFace );
+            nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 ));
+            avoidSet.insert( otherFace );
+          }
+        if ( facesNearLink.size() > 1 )
+        {
+          // NON-MANIFOLD mesh shell !
+          // select a face most co-directed with theFace,
+          // other faces won't be visited this time
+          gp_XYZ NF, NOF;
+          SMESH_MeshAlgos::FaceNormal( theFace, NF, /*normalized=*/false );
+          double proj, maxProj = -1;
+          for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
+            SMESH_MeshAlgos::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
+            if (( proj = Abs( NF * NOF )) > maxProj ) {
+              maxProj = proj;
+              otherFace = facesNearLink[i];
+              nodeInd1  = nodeIndsOfFace[i].first;
+              nodeInd2  = nodeIndsOfFace[i].second;
+            }
+          }
+          // not to visit rejected faces
+          for ( size_t i = 0; i < facesNearLink.size(); ++i )
+            if ( facesNearLink[i] != otherFace && theFaces.size() > 1 )
+              visitedFaces.insert( facesNearLink[i] );
+        }
+        else if ( facesNearLink.size() == 1 )
+        {
+          otherFace = facesNearLink[0];
+          nodeInd1  = nodeIndsOfFace.back().first;
+          nodeInd2  = nodeIndsOfFace.back().second;
+        }
         if ( otherFace && otherFace != theFace)
         {
-          // link must be reversed in otherFace if orientation ot otherFace
+          // link must be reverse in otherFace if orientation ot otherFace
           // is same as that of theFace
           if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
           {
-            // cout << "Reorient " << otherFace->GetID() << " near theFace=" <<theFace->GetID()
-            //      << " \tlink( " << link.first->GetID() << " " << link.second->GetID() << endl;
             nbReori += Reorient( otherFace );
           }
           startFaces.insert( otherFace );
-          if ( theFaces.size() > 1 ) // leave 1 face to prevent finding not selected faces
-            theFaces.erase( otherFace );
         }
       }
-      std::swap( link.first, link.second );
+      std::swap( link.first, link.second ); // reverse the link
     }
-    startFaces.erase( startFace );
-    startFace = startFaces.begin();
   }
   return nbReori;
 }
 
+//================================================================================
+/*!
+ * \brief Reorient faces basing on orientation of adjacent volumes.
+ * \param theFaces - faces to reorient. If empty, all mesh faces are treated.
+ * \param theVolumes - reference volumes.
+ * \param theOutsideNormal - to orient faces to have their normal
+ *        pointing either \a outside or \a inside the adjacent volumes.
+ * \return number of reoriented faces.
+ */
+//================================================================================
+
+int SMESH_MeshEditor::Reorient2DBy3D (TIDSortedElemSet & theFaces,
+                                      TIDSortedElemSet & theVolumes,
+                                      const bool         theOutsideNormal)
+{
+  int nbReori = 0;
+
+  SMDS_ElemIteratorPtr faceIt;
+  if ( theFaces.empty() )
+    faceIt = GetMeshDS()->elementsIterator( SMDSAbs_Face );
+  else
+    faceIt = elemSetIterator( theFaces );
+
+  vector< const SMDS_MeshNode* > faceNodes;
+  TIDSortedElemSet checkedVolumes;
+  set< const SMDS_MeshNode* > faceNodesSet;
+  SMDS_VolumeTool volumeTool;
+
+  while ( faceIt->more() ) // loop on given faces
+  {
+    const SMDS_MeshElement* face = faceIt->next();
+    if ( face->GetType() != SMDSAbs_Face )
+      continue;
+
+    const int nbCornersNodes = face->NbCornerNodes();
+    faceNodes.assign( face->begin_nodes(), face->end_nodes() );
+
+    checkedVolumes.clear();
+    SMDS_ElemIteratorPtr vIt = faceNodes[ 0 ]->GetInverseElementIterator( SMDSAbs_Volume );
+    while ( vIt->more() )
+    {
+      const SMDS_MeshElement* volume = vIt->next();
+
+      if ( !checkedVolumes.insert( volume ).second )
+        continue;
+      if ( !theVolumes.empty() && !theVolumes.count( volume ))
+        continue;
+
+      // is volume adjacent?
+      bool allNodesCommon = true;
+      for ( int iN = 1; iN < nbCornersNodes && allNodesCommon; ++iN )
+        allNodesCommon = ( volume->GetNodeIndex( faceNodes[ iN ]) > -1 );
+      if ( !allNodesCommon )
+        continue;
+
+      // get nodes of a corresponding volume facet
+      faceNodesSet.clear();
+      faceNodesSet.insert( faceNodes.begin(), faceNodes.end() );
+      volumeTool.Set( volume );
+      int facetID = volumeTool.GetFaceIndex( faceNodesSet );
+      if ( facetID < 0 ) continue;
+      volumeTool.SetExternalNormal();
+      const SMDS_MeshNode** facetNodes = volumeTool.GetFaceNodes( facetID );
+
+      // compare order of faceNodes and facetNodes
+      const int iQ = 1 + ( nbCornersNodes < faceNodes.size() );
+      int iNN[2];
+      for ( int i = 0; i < 2; ++i )
+      {
+        const SMDS_MeshNode* n = facetNodes[ i*iQ ];
+        for ( int iN = 0; iN < nbCornersNodes; ++iN )
+          if ( faceNodes[ iN ] == n )
+          {
+            iNN[ i ] = iN;
+            break;
+          }
+      }
+      bool isOutside = Abs( iNN[0]-iNN[1] ) == 1 ? iNN[0] < iNN[1] : iNN[0] > iNN[1];
+      if ( isOutside != theOutsideNormal )
+        nbReori += Reorient( face );
+    }
+  }  // loop on given faces
+
+  return nbReori;
+}
+
 //=======================================================================
 //function : getBadRate
 //purpose  :
@@ -1178,8 +1404,6 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
-  MESSAGE( "::QuadToTri()" );
-
   if ( !theCrit.get() )
     return false;
 
@@ -1189,7 +1413,8 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
   SMESH_MesherHelper   helper( *GetMesh() );
 
   TIDSortedElemSet::iterator itElem;
-  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
+  {
     const SMDS_MeshElement* elem = *itElem;
     if ( !elem || elem->GetType() != SMDSAbs_Face )
       continue;
@@ -1209,14 +1434,14 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
 
-    int aShapeId = FindShape( elem );
+    const int aShapeId = FindShape( elem );
     const SMDS_MeshElement* newElem1 = 0;
     const SMDS_MeshElement* newElem2 = 0;
 
-    if( !elem->IsQuadratic() ) {
-
-      // split liner quadrangle
-
+    if ( !elem->IsQuadratic() ) // split liner quadrangle
+    {
+      // for MaxElementLength2D functor we return minimum diagonal for splitting,
+      // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
       if ( aBadRate1 <= aBadRate2 ) {
         // tr1 + tr2 is better
         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
@@ -1228,70 +1453,28 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
       }
     }
-    else {
-
-      // split quadratic quadrangle
+    else // split quadratic quadrangle
+    {
+      helper.SetIsQuadratic( true );
+      helper.SetIsBiQuadratic( aNodes.size() == 9 );
 
-      // get surface elem is on
-      if ( aShapeId != helper.GetSubShapeID() ) {
-        surface.Nullify();
-        TopoDS_Shape shape;
-        if ( aShapeId > 0 )
-          shape = aMesh->IndexToShape( aShapeId );
-        if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
-          TopoDS_Face face = TopoDS::Face( shape );
-          surface = BRep_Tool::Surface( face );
-          if ( !surface.IsNull() )
-            helper.SetSubShape( shape );
-        }
-      }
-      // find middle point for (0,1,2,3)
-      // and create a node in this point;
-      const SMDS_MeshNode* newN = 0;
+      helper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem ));
       if ( aNodes.size() == 9 )
       {
-        // SMDSEntity_BiQuad_Quadrangle
-        newN = aNodes.back();
-      }
-      else
-      {
-        gp_XYZ p( 0,0,0 );
-        if ( surface.IsNull() )
-        {
-          for ( int i = 0; i < 4; i++ )
-            p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
-          p /= 4;
-        }
+        helper.SetIsBiQuadratic( true );
+        if ( aBadRate1 <= aBadRate2 )
+          helper.AddTLinkNode( aNodes[0], aNodes[2], aNodes[8] );
         else
-        {
-          const SMDS_MeshNode* inFaceNode = 0;
-          if ( helper.GetNodeUVneedInFaceNode() )
-            for ( size_t i = 0; i < aNodes.size() && !inFaceNode; ++i )
-              if ( aNodes[ i ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
-                inFaceNode = aNodes[ i ];
-
-          TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
-          gp_XY uv( 0,0 );
-          for ( int i = 0; i < 4; i++ )
-            uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
-          uv /= 4.;
-          p = surface->Value( uv.X(), uv.Y() ).XYZ();
-        }
-        newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
-        myLastCreatedNodes.Append(newN);
+          helper.AddTLinkNode( aNodes[1], aNodes[3], aNodes[8] );
       }
       // create a new element
       if ( aBadRate1 <= aBadRate2 ) {
-        newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
-                                  aNodes[6], aNodes[7], newN );
-        newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
-                                  newN,      aNodes[4], aNodes[5] );
+        newElem1 = helper.AddFace( aNodes[2], aNodes[3], aNodes[0] );
+        newElem2 = helper.AddFace( aNodes[2], aNodes[0], aNodes[1] );
       }
       else {
-        newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
-                                  aNodes[7], aNodes[4], newN );
-        newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
-                                  newN,      aNodes[5], aNodes[6] );
+        newElem1 = helper.AddFace( aNodes[3], aNodes[0], aNodes[1] );
+        newElem2 = helper.AddFace( aNodes[3], aNodes[1], aNodes[2] );
       }
     } // quadratic case
 
@@ -1304,43 +1487,166 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
 
     // put a new triangle on the same shape
     if ( aShapeId )
-      {
-        aMesh->SetMeshElementOnShape( newElem1, aShapeId );
-        aMesh->SetMeshElementOnShape( newElem2, aShapeId );
-      }
+      aMesh->SetMeshElementOnShape( newElem1, aShapeId );
+    aMesh->SetMeshElementOnShape( newElem2, aShapeId );
+
     aMesh->RemoveElement( elem );
   }
   return true;
 }
 
 //=======================================================================
-//function : BestSplit
-//purpose  : Find better diagonal for cutting.
+/*!
+ * \brief Split each of given quadrangles into 4 triangles.
+ * \param theElems - The faces to be splitted. If empty all faces are split.
+ */
 //=======================================================================
 
-int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
-                                 SMESH::Controls::NumericalFunctorPtr theCrit)
+void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
 {
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
-  if (!theCrit.get())
-    return -1;
+  SMESH_MesherHelper helper( *GetMesh() );
+  helper.SetElementsOnShape( true );
 
-  if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
-    return -1;
+  SMDS_ElemIteratorPtr faceIt;
+  if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face);
+  else                    faceIt = elemSetIterator( theElems );
 
-  if( theQuad->NbNodes()==4 ||
-      (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
+  bool   checkUV;
+  gp_XY  uv [9]; uv[8] = gp_XY(0,0);
+  gp_XYZ xyz[9];
+  vector< const SMDS_MeshNode* > nodes;
+  SMESHDS_SubMesh*               subMeshDS;
+  TopoDS_Face                    F;
+  Handle(Geom_Surface)           surface;
+  TopLoc_Location                loc;
 
-    // retrieve element nodes
-    const SMDS_MeshNode* aNodes [4];
-    SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
-    int i = 0;
-    //while (itN->more())
-    while (i<4) {
-      aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
-    }
+  while ( faceIt->more() )
+  {
+    const SMDS_MeshElement* quad = faceIt->next();
+    if ( !quad || quad->NbCornerNodes() != 4 )
+      continue;
+
+    // get a surface the quad is on
+
+    if ( quad->getshapeId() < 1 )
+    {
+      F.Nullify();
+      helper.SetSubShape( 0 );
+      subMeshDS = 0;
+    }
+    else if ( quad->getshapeId() != helper.GetSubShapeID() )
+    {
+      helper.SetSubShape( quad->getshapeId() );
+      if ( !helper.GetSubShape().IsNull() &&
+           helper.GetSubShape().ShapeType() == TopAbs_FACE )
+      {
+        F = TopoDS::Face( helper.GetSubShape() );
+        surface = BRep_Tool::Surface( F, loc );
+        subMeshDS = GetMeshDS()->MeshElements( quad->getshapeId() );
+      }
+      else
+      {
+        helper.SetSubShape( 0 );
+        subMeshDS = 0;
+      }
+    }
+
+    // create a central node
+
+    const SMDS_MeshNode* nCentral;
+    nodes.assign( quad->begin_nodes(), quad->end_nodes() );
+
+    if ( nodes.size() == 9 )
+    {
+      nCentral = nodes.back();
+    }
+    else
+    {
+      size_t iN = 0;
+      if ( F.IsNull() )
+      {
+        for ( ; iN < nodes.size(); ++iN )
+          xyz[ iN ] = SMESH_TNodeXYZ( nodes[ iN ] );
+
+        for ( ; iN < 8; ++iN ) // mid-side points of a linear qudrangle
+          xyz[ iN ] = 0.5 * ( xyz[ iN - 4 ] + xyz[( iN - 3 )%4 ] );
+
+        xyz[ 8 ] = helper.calcTFI( 0.5, 0.5,
+                                   xyz[0], xyz[1], xyz[2], xyz[3],
+                                   xyz[4], xyz[5], xyz[6], xyz[7] );
+      }
+      else
+      {
+        for ( ; iN < nodes.size(); ++iN )
+          uv[ iN ] = helper.GetNodeUV( F, nodes[iN], nodes[(iN+2)%4], &checkUV );
+
+        for ( ; iN < 8; ++iN ) // UV of mid-side points of a linear qudrangle
+          uv[ iN ] = helper.GetMiddleUV( surface, uv[ iN - 4 ], uv[( iN - 3 )%4 ] );
+
+        uv[ 8 ] = helper.calcTFI( 0.5, 0.5,
+                                  uv[0], uv[1], uv[2], uv[3],
+                                  uv[4], uv[5], uv[6], uv[7] );
+
+        gp_Pnt p = surface->Value( uv[8].X(), uv[8].Y() ).Transformed( loc );
+        xyz[ 8 ] = p.XYZ();
+      }
+
+      nCentral = helper.AddNode( xyz[8].X(), xyz[8].Y(), xyz[8].Z(), /*id=*/0,
+                                 uv[8].X(), uv[8].Y() );
+      myLastCreatedNodes.Append( nCentral );
+    }
+
+    // create 4 triangles
+
+    GetMeshDS()->RemoveFreeElement( quad, subMeshDS, /*fromGroups=*/false );
+    
+    helper.SetIsQuadratic  ( nodes.size() > 4 );
+    helper.SetIsBiQuadratic( nodes.size() == 9 );
+    if ( helper.GetIsQuadratic() )
+      helper.AddTLinks( static_cast< const SMDS_MeshFace*>( quad ));
+
+    for ( int i = 0; i < 4; ++i )
+    {
+      SMDS_MeshElement* tria = helper.AddFace( nodes[ i ],
+                                               nodes[(i+1)%4],
+                                               nCentral );
+      ReplaceElemInGroups( tria, quad, GetMeshDS() );
+      myLastCreatedElems.Append( tria );
+    }
+  }
+}
+
+//=======================================================================
+//function : BestSplit
+//purpose  : Find better diagonal for cutting.
+//=======================================================================
+
+int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
+                                 SMESH::Controls::NumericalFunctorPtr theCrit)
+{
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
+  if (!theCrit.get())
+    return -1;
+
+  if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
+    return -1;
+
+  if( theQuad->NbNodes()==4 ||
+      (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
+
+    // retrieve element nodes
+    const SMDS_MeshNode* aNodes [4];
+    SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
+    int i = 0;
+    //while (itN->more())
+    while (i<4) {
+      aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
+    }
     // compare two sets of possible triangles
     double aBadRate1, aBadRate2; // to what extent a set is bad
     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
@@ -1350,7 +1656,8 @@ int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
-
+    // for MaxElementLength2D functor we return minimum diagonal for splitting,
+    // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
       return 1; // diagonal 1-3
 
@@ -1428,44 +1735,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, 9, 1, 2, 8,    3, 7, 9, 2, 6, 8,    7, 4, 9, 6, 5, 8,   4, 0, 9, 5, 1, 8,    -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;
 
@@ -1490,8 +1863,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
       {
@@ -1504,7 +1877,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 );
@@ -1544,12 +1917,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 )
@@ -1563,7 +1936,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
@@ -1657,7 +2030,7 @@ namespace
             connectivity[ connSize++ ] = baryCenInd;
           }
         }
-        method._nbTetra += nbTet;
+        method._nbSplits += nbTet;
 
       } // loop on volume faces
 
@@ -1667,13 +2040,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);
@@ -1683,16 +2175,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;
     }
@@ -1725,52 +2217,56 @@ 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;
-  
+
   SMESH_SequenceOfElemPtr newNodes, newElems;
 
   // map face of volume to it's baricenrtic node
   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
@@ -1788,7 +2284,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->NbNodes() );
     helper.SetElementsOnShape( true );
     if ( splitMethod._baryNode )
     {
@@ -1816,16 +2313,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
 
@@ -1854,17 +2360,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
@@ -1894,6 +2420,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 ))
@@ -1912,11 +2440,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 )
     {
@@ -1926,11 +2454,203 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
           GetMeshDS()->RemoveNode( volNodes[i] );
     }
   } // loop on volumes to split
-
+  
   myLastCreatedNodes = newNodes;
   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
@@ -2287,18 +3007,19 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
 
   TIDSortedElemSet::iterator itElem;
-  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
+  {
     const SMDS_MeshElement* elem = *itElem;
     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
-    bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
-    if(!IsTria) continue;
+    bool IsTria = ( elem->NbCornerNodes()==3 );
+    if (!IsTria) continue;
 
     // retrieve element nodes
     const SMDS_MeshNode* aNodes [4];
-    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+    SMDS_NodeIteratorPtr itN = elem->nodeIterator();
     int i = 0;
-    while ( i<3 )
-      aNodes[ i++ ] = cast2Node( itN->next() );
+    while ( i < 3 )
+      aNodes[ i++ ] = itN->next();
     aNodes[ 3 ] = aNodes[ 0 ];
 
     // fill maps
@@ -2443,31 +3164,31 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
         }
 
         // Make quadrangles
-        // and remove fused elems and removed links from the maps
+        // and remove fused elems and remove links from the maps
         mapEl_setLi.erase( tr1 );
-        if ( Ok12 ) {
+        if ( Ok12 )
+        {
           mapEl_setLi.erase( tr2 );
           mapLi_listEl.erase( *link12 );
-          if(tr1->NbNodes()==3) {
+          if ( tr1->NbNodes() == 3 )
+          {
             const SMDS_MeshElement* newElem = 0;
             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
             myLastCreatedElems.Append(newElem);
             AddToSameGroups( newElem, tr1, aMesh );
             int aShapeId = tr1->getshapeId();
             if ( aShapeId )
-              {
-                aMesh->SetMeshElementOnShape( newElem, aShapeId );
-              }
+              aMesh->SetMeshElementOnShape( newElem, aShapeId );
             aMesh->RemoveElement( tr1 );
             aMesh->RemoveElement( tr2 );
           }
           else {
-            const SMDS_MeshNode* N1 [6];
-            const SMDS_MeshNode* N2 [6];
-            GetNodesFromTwoTria(tr1,tr2,N1,N2);
-            // now we receive following N1 and N2 (using numeration as above image)
+            vector< const SMDS_MeshNode* > N1;
+            vector< const SMDS_MeshNode* > N2;
+            getNodesFromTwoTria(tr1,tr2,N1,N2);
+            // now we receive following N1 and N2 (using numeration as in image in InverseDiag())
             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
-            // i.e. first nodes from both arrays determ new diagonal
+            // i.e. first nodes from both arrays form a new diagonal
             const SMDS_MeshNode* aNodes[8];
             aNodes[0] = N1[0];
             aNodes[1] = N1[1];
@@ -2478,44 +3199,50 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
             aNodes[6] = N2[3];
             aNodes[7] = N1[5];
             const SMDS_MeshElement* newElem = 0;
-            newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
-                                     aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
+            if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
+              newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
+                                       aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
+            else
+              newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
+                                       aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
             myLastCreatedElems.Append(newElem);
             AddToSameGroups( newElem, tr1, aMesh );
             int aShapeId = tr1->getshapeId();
             if ( aShapeId )
-              {
-                aMesh->SetMeshElementOnShape( newElem, aShapeId );
-              }
+              aMesh->SetMeshElementOnShape( newElem, aShapeId );
             aMesh->RemoveElement( tr1 );
             aMesh->RemoveElement( tr2 );
             // remove middle node (9)
-            GetMeshDS()->RemoveNode( N1[4] );
+            if ( N1[4]->NbInverseElements() == 0 )
+              aMesh->RemoveNode( N1[4] );
+            if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
+              aMesh->RemoveNode( N1[6] );
+            if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
+              aMesh->RemoveNode( N2[6] );
           }
         }
-        else if ( Ok13 ) {
+        else if ( Ok13 )
+        {
           mapEl_setLi.erase( tr3 );
           mapLi_listEl.erase( *link13 );
-          if(tr1->NbNodes()==3) {
+          if ( tr1->NbNodes() == 3 ) {
             const SMDS_MeshElement* newElem = 0;
             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
             myLastCreatedElems.Append(newElem);
             AddToSameGroups( newElem, tr1, aMesh );
             int aShapeId = tr1->getshapeId();
             if ( aShapeId )
-              {
-                aMesh->SetMeshElementOnShape( newElem, aShapeId );
-              }
+              aMesh->SetMeshElementOnShape( newElem, aShapeId );
             aMesh->RemoveElement( tr1 );
             aMesh->RemoveElement( tr3 );
           }
           else {
-            const SMDS_MeshNode* N1 [6];
-            const SMDS_MeshNode* N2 [6];
-            GetNodesFromTwoTria(tr1,tr3,N1,N2);
+            vector< const SMDS_MeshNode* > N1;
+            vector< const SMDS_MeshNode* > N2;
+            getNodesFromTwoTria(tr1,tr3,N1,N2);
             // now we receive following N1 and N2 (using numeration as above image)
             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
-            // i.e. first nodes from both arrays determ new diagonal
+            // i.e. first nodes from both arrays form a new diagonal
             const SMDS_MeshNode* aNodes[8];
             aNodes[0] = N1[0];
             aNodes[1] = N1[1];
@@ -2526,19 +3253,26 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
             aNodes[6] = N2[3];
             aNodes[7] = N1[5];
             const SMDS_MeshElement* newElem = 0;
-            newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
-                                     aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
+            if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
+              newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
+                                       aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
+            else
+              newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
+                                       aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
             myLastCreatedElems.Append(newElem);
             AddToSameGroups( newElem, tr1, aMesh );
             int aShapeId = tr1->getshapeId();
             if ( aShapeId )
-              {
-                aMesh->SetMeshElementOnShape( newElem, aShapeId );
-              }
+              aMesh->SetMeshElementOnShape( newElem, aShapeId );
             aMesh->RemoveElement( tr1 );
             aMesh->RemoveElement( tr3 );
             // remove middle node (9)
-            GetMeshDS()->RemoveNode( N1[4] );
+            if ( N1[4]->NbInverseElements() == 0 )
+              aMesh->RemoveNode( N1[4] );
+            if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
+              aMesh->RemoveNode( N1[6] );
+            if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
+              aMesh->RemoveNode( N2[6] );
           }
         }
 
@@ -2854,7 +3588,7 @@ void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
     const SMDS_MeshElement* elem = elemIt->next();
     if(elem->GetType() == SMDSAbs_0DElement)
       continue;
-    
+
     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
     if ( elem->GetType() == SMDSAbs_Volume )
     {
@@ -3011,13 +3745,8 @@ static bool getClosestUV (Extrema_GenExtPS& projector,
   if ( projector.IsDone() ) {
     double u, v, minVal = DBL_MAX;
     for ( int i = projector.NbExt(); i > 0; i-- )
-#if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
       if ( projector.SquareDistance( i ) < minVal ) {
         minVal = projector.SquareDistance( i );
-#else
-      if ( projector.Value( i ) < minVal ) {
-        minVal = projector.Value( i );
-#endif
         projector.Point( i ).Parameter( u, v );
       }
     result.SetCoord( u, v );
@@ -3062,7 +3791,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
     while ( fIt->more() ) {
       const SMDS_MeshElement* face = fIt->next();
-      theElems.insert( face );
+      theElems.insert( theElems.end(), face );
     }
   }
   // get all face ids theElems are on
@@ -3086,8 +3815,11 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
   // smooth elements on each TopoDS_Face separately
   // ===============================================
 
-  set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
-  for ( ; fId != faceIdSet.rend(); ++fId ) {
+  SMESH_MesherHelper helper( *GetMesh() );
+
+  set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treat 0 fId at the end
+  for ( ; fId != faceIdSet.rend(); ++fId )
+  {
     // get face surface and submesh
     Handle(Geom_Surface) surface;
     SMESHDS_SubMesh* faceSubMesh = 0;
@@ -3095,7 +3827,8 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
     double fToler2 = 0, f,l;
     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
     bool isUPeriodic = false, isVPeriodic = false;
-    if ( *fId ) {
+    if ( *fId )
+    {
       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
       surface = BRep_Tool::Surface( face );
       faceSubMesh = aMesh->MeshElements( *fId );
@@ -3108,6 +3841,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
       if ( isVPeriodic )
         surface->VPeriod();
       surface->Bounds( u1, u2, v1, v2 );
+      helper.SetSubShape( face );
     }
     // ---------------------------------------------------------
     // for elements on a face, find movable and fixed nodes and
@@ -3129,7 +3863,8 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
     int nbElemOnFace = 0;
     itElem = theElems.begin();
     // loop on not yet smoothed elements: look for elems on a face
-    while ( itElem != theElems.end() ) {
+    while ( itElem != theElems.end() )
+    {
       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
         break; // all elements found
 
@@ -3185,12 +3920,15 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
 
       // get nodes to check UV
       list< const SMDS_MeshNode* > uvCheckNodes;
+      const SMDS_MeshNode* nodeInFace = 0;
       itN = elem->nodesIterator();
       nn = 0; nbn =  elem->NbNodes();
       if(elem->IsQuadratic())
         nbn = nbn/2;
       while ( nn++ < nbn ) {
         node = static_cast<const SMDS_MeshNode*>( itN->next() );
+        if ( node->GetPosition()->GetDim() == 2 )
+          nodeInFace = node;
         if ( uvMap.find( node ) == uvMap.end() )
           uvCheckNodes.push_back( node );
         // add nodes of elems sharing node
@@ -3216,41 +3954,21 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
         const SMDS_PositionPtr& pos = node->GetPosition();
         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
         // get existing UV
-        switch ( posType ) {
-        case SMDS_TOP_FACE: {
-          SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
-          uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
-          break;
-        }
-        case SMDS_TOP_EDGE: {
-          TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
-          Handle(Geom2d_Curve) pcurve;
-          if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
-            pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
-          if ( !pcurve.IsNull() ) {
-            double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
-            uv = pcurve->Value( u ).XY();
-          }
-          break;
-        }
-        case SMDS_TOP_VERTEX: {
-          TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
-          if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
-            uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
-          break;
-        }
-        default:;
-        }
-        // check existing UV
-        bool project = true;
-        gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
-        double dist1 = DBL_MAX, dist2 = 0;
-        if ( posType != SMDS_TOP_3DSPACE ) {
-          dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
-          project = dist1 > fToler2;
-        }
+        if ( pos )
+        {
+          bool toCheck = true;
+          uv = helper.GetNodeUV( face, node, nodeInFace, &toCheck );
+        }
+        // compute not existing UV
+        bool project = ( posType == SMDS_TOP_3DSPACE );
+        // double dist1 = DBL_MAX, dist2 = 0;
+        // if ( posType != SMDS_TOP_3DSPACE ) {
+        //   dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
+        //   project = dist1 > fToler2;
+        // }
         if ( project ) { // compute new UV
           gp_XY newUV;
+          gp_Pnt pNode = SMESH_TNodeXYZ( node );
           if ( !getClosestUV( projector, pNode, newUV )) {
             MESSAGE("Node Projection Failed " << node);
           }
@@ -3260,9 +3978,9 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
             if ( isVPeriodic )
               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
             // check new UV
-            if ( posType != SMDS_TOP_3DSPACE )
-              dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
-            if ( dist2 < dist1 )
+            // if ( posType != SMDS_TOP_3DSPACE )
+            //   dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
+            // if ( dist2 < dist1 )
               uv = newUV;
           }
         }
@@ -3330,9 +4048,8 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
         uv2 = pcurve->Value( f );
         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
         // assure uv1 < uv2
-        if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
-          gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
-        }
+        if ( uv1.Coord( iPar ) > uv2.Coord( iPar ))
+          std::swap( uv1, uv2 );
         // get nodes on seam and its vertices
         list< const SMDS_MeshNode* > seamNodes;
         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
@@ -3382,12 +4099,14 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
                   setMovableNodes.find( n ) == setMovableNodes.end() )
                 continue;
               // add only nodes being closer to uv2 than to uv1
-              gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
-                           0.5 * ( n->Y() + nSeam->Y() ),
-                           0.5 * ( n->Z() + nSeam->Z() ));
-              gp_XY uv;
-              getClosestUV( projector, pMid, uv );
-              if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
+              // gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
+              //              0.5 * ( n->Y() + nSeam->Y() ),
+              //              0.5 * ( n->Z() + nSeam->Z() ));
+              // gp_XY uv;
+              // getClosestUV( projector, pMid, uv );
+              double x = uvMap[ n ]->Coord( iPar );
+              if ( Abs( uv1.Coord( iPar ) - x ) >
+                   Abs( uv2.Coord( iPar ) - x )) {
                 nodesNearSeam.insert( n );
                 nbUseMap2++;
               }
@@ -3496,40 +4215,33 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
     // move medium nodes of quadratic elements
     if ( isQuadratic )
     {
-      SMESH_MesherHelper helper( *GetMesh() );
-      if ( !face.IsNull() )
-        helper.SetSubShape( face );
+      vector<const SMDS_MeshNode*> nodes;
+      bool checkUV;
       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
-      for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
-        const SMDS_VtkFace* QF =
-          dynamic_cast<const SMDS_VtkFace*> (*elemIt);
-        if(QF && QF->IsQuadratic()) {
-          vector<const SMDS_MeshNode*> Ns;
-          Ns.reserve(QF->NbNodes()+1);
-          SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
-          while ( anIter->more() )
-            Ns.push_back( cast2Node(anIter->next()) );
-          Ns.push_back( Ns[0] );
-          double x, y, z;
-          for(int i=0; i<QF->NbNodes(); i=i+2) {
-            if ( !surface.IsNull() ) {
-              gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
-              gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
-              gp_XY uv = ( uv1 + uv2 ) / 2.;
-              gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
-              x = xyz.X(); y = xyz.Y(); z = xyz.Z();
+      for ( ; elemIt != elemsOnFace.end(); ++elemIt )
+      {
+        const SMDS_MeshElement* QF = *elemIt;
+        if ( QF->IsQuadratic() )
+        {
+          nodes.assign( SMDS_MeshElement::iterator( QF->interlacedNodesElemIterator() ),
+                        SMDS_MeshElement::iterator() );
+          nodes.push_back( nodes[0] );
+          gp_Pnt xyz;
+          for (size_t i = 1; i < nodes.size(); i += 2 ) // i points to a medium node
+          {
+            if ( !surface.IsNull() )
+            {
+              gp_XY uv1 = helper.GetNodeUV( face, nodes[i-1], nodes[i+1], &checkUV );
+              gp_XY uv2 = helper.GetNodeUV( face, nodes[i+1], nodes[i-1], &checkUV );
+              gp_XY uv  = helper.GetMiddleUV( surface, uv1, uv2 );
+              xyz = surface->Value( uv.X(), uv.Y() );
             }
             else {
-              x = (Ns[i]->X() + Ns[i+2]->X())/2;
-              y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
-              z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
-            }
-            if( fabs( Ns[i+1]->X() - x ) > disttol ||
-                fabs( Ns[i+1]->Y() - y ) > disttol ||
-                fabs( Ns[i+1]->Z() - z ) > disttol ) {
-              // we have to move i+1 node
-              aMesh->MoveNode( Ns[i+1], x, y, z );
+              xyz = 0.5 * ( SMESH_TNodeXYZ( nodes[i-1] ) + SMESH_TNodeXYZ( nodes[i+1] ));
             }
+            if (( SMESH_TNodeXYZ( nodes[i] ) - xyz.XYZ() ).Modulus() > disttol )
+              // we have to move a medium node
+              aMesh->MoveNode( nodes[i], xyz.X(), xyz.Y(), xyz.Z() );
           }
         }
       }
@@ -3539,26 +4251,49 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
 
 }
 
-//=======================================================================
-//function : isReverse
-//purpose  : Return true if normal of prevNodes is not co-directied with
-//           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
-//           iNotSame is where prevNodes and nextNodes are different.
-//           If result is true then future volume orientation is OK
-//=======================================================================
-
-static bool isReverse(const SMDS_MeshElement*             face,
-                      const vector<const SMDS_MeshNode*>& prevNodes,
-                      const vector<const SMDS_MeshNode*>& nextNodes,
-                      const int                           iNotSame)
+namespace
 {
+  //=======================================================================
+  //function : isReverse
+  //purpose  : Return true if normal of prevNodes is not co-directied with
+  //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
+  //           iNotSame is where prevNodes and nextNodes are different.
+  //           If result is true then future volume orientation is OK
+  //=======================================================================
+
+  bool isReverse(const SMDS_MeshElement*             face,
+                 const vector<const SMDS_MeshNode*>& prevNodes,
+                 const vector<const SMDS_MeshNode*>& nextNodes,
+                 const int                           iNotSame)
+  {
+
+    SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
+    SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
+    gp_XYZ extrDir( pN - pP ), faceNorm;
+    SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false );
 
-  SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
-  SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
-  gp_XYZ extrDir( pN - pP ), faceNorm;
-  SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false );
+    return faceNorm * extrDir < 0.0;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Assure that theElemSets[0] holds elements, not nodes
+   */
+  //================================================================================
 
-  return faceNorm * extrDir < 0.0;
+  void setElemsFirst( TIDSortedElemSet theElemSets[2] )
+  {
+    if ( !theElemSets[0].empty() &&
+         (*theElemSets[0].begin())->GetType() == SMDSAbs_Node )
+    {
+      std::swap( theElemSets[0], theElemSets[1] );
+    }
+    else if ( !theElemSets[1].empty() &&
+              (*theElemSets[1].begin())->GetType() != SMDSAbs_Node )
+    {
+      std::swap( theElemSets[0], theElemSets[1] );
+    }
+  }
 }
 
 //=======================================================================
@@ -3581,9 +4316,9 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
   //MESSAGE("sweepElement " << nbSteps);
   SMESHDS_Mesh* aMesh = GetMeshDS();
 
-  const int           nbNodes = elem->NbNodes();          
+  const int           nbNodes = elem->NbNodes();
   const int         nbCorners = elem->NbCornerNodes();
-  SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of 
+  SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of
                                                           polyhedron creation !!! */
   // Loop on elem nodes:
   // find new nodes and detect same nodes indices
@@ -3638,7 +4373,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
     }
     else
     {
-      const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
+      const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType, nbNodes );
       SMDS_MeshCell::applyInterlace( ind, itNN );
       SMDS_MeshCell::applyInterlace( ind, prevNod );
       SMDS_MeshCell::applyInterlace( ind, nextNod );
@@ -3658,6 +4393,30 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
       }
     }
   }
+  else if ( elem->GetType() == SMDSAbs_Edge )
+  {
+    // orient a new face same as adjacent one
+    int i1, i2;
+    const SMDS_MeshElement* e;
+    TIDSortedElemSet dummy;
+    if (( e = SMESH_MeshAlgos::FindFaceInSet( nextNod[0], prevNod[0], dummy,dummy, &i1, &i2 )) ||
+        ( e = SMESH_MeshAlgos::FindFaceInSet( prevNod[1], nextNod[1], dummy,dummy, &i1, &i2 )) ||
+        ( e = SMESH_MeshAlgos::FindFaceInSet( prevNod[0], prevNod[1], dummy,dummy, &i1, &i2 )))
+    {
+      // there is an adjacent face, check order of nodes in it
+      bool sameOrder = ( Abs( i2 - i1 ) == 1 ) ? ( i2 > i1 ) : ( i2 < i1 );
+      if ( sameOrder )
+      {
+        std::swap( itNN[0],    itNN[1] );
+        std::swap( prevNod[0], prevNod[1] );
+        std::swap( nextNod[0], nextNod[1] );
+        isSingleNode.swap( isSingleNode[0], isSingleNode[1] );
+        if ( nbSame > 0 )
+          sames[0] = 1 - sames[0];
+        iNotSameNode = 1 - iNotSameNode;
+      }
+    }
+  }
 
   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
   if ( nbSame > 0 ) {
@@ -3667,6 +4426,17 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
   }
 
+  if ( baseType == SMDSEntity_Polygon )
+  {
+    if      ( nbNodes == 3 ) baseType = SMDSEntity_Triangle;
+    else if ( nbNodes == 4 ) baseType = SMDSEntity_Quadrangle;
+  }
+  else if ( baseType == SMDSEntity_Quad_Polygon )
+  {
+    if      ( nbNodes == 6 ) baseType = SMDSEntity_Quad_Triangle;
+    else if ( nbNodes == 8 ) baseType = SMDSEntity_Quad_Quadrangle;
+  }
+
   // make new elements
   for (int iStep = 0; iStep < nbSteps; iStep++ )
   {
@@ -3763,11 +4533,11 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
                 return; // medium node on axis
               }
               else if(sames[0]==0)
-                aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
-                                          nextNod[2], midlNod[1], prevNod[2]);
+                aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1],
+                                          prevNod[2], midlNod[1], nextNod[2] );
               else // sames[0]==1
-                aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
-                                          midlNod[0], nextNod[2], prevNod[2]);
+                aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[0],
+                                          prevNod[2], nextNod[2], midlNod[0]);
             }
           }
           else if ( nbDouble == 3 )
@@ -3811,7 +4581,8 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
         }
         break;
       }
-      case SMDSEntity_Quad_Triangle: { // sweep Quadratic TRIANGLE --->
+      case SMDSEntity_Quad_Triangle:  // sweep (Bi)Quadratic TRIANGLE --->
+      case SMDSEntity_BiQuad_Triangle: /* ??? */ {
         if ( nbDouble+nbSame != 3 ) break;
         if(nbSame==0) {
           // --->  pentahedron with 15 nodes
@@ -3861,7 +4632,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
         }
         else if(nbSame==1) {
-          // ---> pyramid + pentahedron - can not be created since it is needed 
+          // ---> pyramid + pentahedron - can not be created since it is needed
           // additional middle node at the center of face
           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
           return;
@@ -3932,14 +4703,14 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
 
       default:
         break;
-      }
-    }
+      } // switch ( baseType )
+    } // scope
 
     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
     {
       if ( baseType != SMDSEntity_Polygon )
       {
-        const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
+        const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType,nbNodes);
         SMDS_MeshCell::applyInterlace( ind, prevNod );
         SMDS_MeshCell::applyInterlace( ind, nextNod );
         SMDS_MeshCell::applyInterlace( ind, midlNod );
@@ -3964,21 +4735,30 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
       quantities.push_back( nbNodes );
 
       // side faces
-      for (int iface = 0; iface < nbNodes; iface++)
+      // 3--6--2
+      // |     |
+      // 7     5
+      // |     |
+      // 0--4--1
+      const int iQuad = elem->IsQuadratic();
+      for (int iface = 0; iface < nbNodes; iface += 1+iQuad )
       {
-        const int prevNbNodes = polyedre_nodes.size();
-        int inextface = (iface+1) % nbNodes;
-        polyedre_nodes.push_back( prevNod[inextface] );
-        polyedre_nodes.push_back( prevNod[iface] );
-        if ( prevNod[iface] != nextNod[iface] )
+        const int prevNbNodes = polyedre_nodes.size(); // to detect degenerated face
+        int inextface = (iface+1+iQuad) % nbNodes;
+        int imid      = (iface+1) % nbNodes;
+        polyedre_nodes.push_back( prevNod[inextface] );         // 0
+        if ( iQuad ) polyedre_nodes.push_back( prevNod[imid] ); // 4
+        polyedre_nodes.push_back( prevNod[iface] );             // 1
+        if ( prevNod[iface] != nextNod[iface] ) // 1 != 2
         {
-          if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
-          polyedre_nodes.push_back( nextNod[iface] );
+          if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]); // 5
+          polyedre_nodes.push_back( nextNod[iface] );                         // 2
         }
-        if ( prevNod[inextface] != nextNod[inextface] )
+        if ( iQuad ) polyedre_nodes.push_back( nextNod[imid] );               // 6
+        if ( prevNod[inextface] != nextNod[inextface] ) // 0 != 3
         {
-          polyedre_nodes.push_back( nextNod[inextface] );
-          if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
+          polyedre_nodes.push_back( nextNod[inextface] );                            // 3
+          if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);// 7
         }
         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
         if ( nbFaceNodes > 2 )
@@ -3987,7 +4767,8 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
           polyedre_nodes.resize( prevNbNodes );
       }
       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
-    }
+
+    } // try to create a polyherdal prism
 
     if ( aNewElem ) {
       newElems.push_back( aNewElem );
@@ -3999,7 +4780,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
     for ( iNode = 0; iNode < nbNodes; iNode++ )
       prevNod[ iNode ] = nextNod[ iNode ];
 
-  } // for steps
+  } // loop on steps
 }
 
 //=======================================================================
@@ -4015,7 +4796,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
 //=======================================================================
 
 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
-                                  TElemOfElemListMap &     newElemsMap,
+                                  TTElemOfElemListMap &    newElemsMap,
                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
                                   TIDSortedElemSet&        elemSet,
                                   const int                nbSteps,
@@ -4024,25 +4805,28 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
   SMESHDS_Mesh* aMesh = GetMeshDS();
 
-  // Find nodes belonging to only one initial element - sweep them to get edges.
+  // Find nodes belonging to only one initial element - sweep them into edges.
 
   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
   for ( ; nList != mapNewNodes.end(); nList++ )
   {
     const SMDS_MeshNode* node =
       static_cast<const SMDS_MeshNode*>( nList->first );
+    if ( newElemsMap.count( node ))
+      continue; // node was extruded into edge
     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
     int nbInitElems = 0;
     const SMDS_MeshElement* el = 0;
     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
     while ( eIt->more() && nbInitElems < 2 ) {
-      el = eIt->next();
-      SMDSAbs_ElementType type = el->GetType();
+      const SMDS_MeshElement* e = eIt->next();
+      SMDSAbs_ElementType type = e->GetType();
       if ( type == SMDSAbs_Volume || type < highType ) continue;
       if ( type > highType ) {
         nbInitElems = 0;
         highType = type;
       }
+      el = e;
       nbInitElems += elemSet.count(el);
     }
     if ( nbInitElems < 2 ) {
@@ -4058,7 +4842,9 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
   // Make a ceiling for each element ie an equal element of last new nodes.
   // Find free links of faces - make edges and sweep them into faces.
 
-  TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
+  ElemFeatures polyFace( SMDSAbs_Face, /*isPoly=*/true ), anyFace;
+
+  TTElemOfElemListMap::iterator  itElem      = newElemsMap.begin();
   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
   {
@@ -4076,7 +4862,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
                                vecNewNodes[ 1 ]->second.back())) {
           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
                                                    vecNewNodes[ 1 ]->second.back()));
-          srcElements.Append( myLastCreatedElems.Last() );
+          srcElements.Append( elem );
         }
       }
       else {
@@ -4086,7 +4872,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
                                                    vecNewNodes[ 1 ]->second.back(),
                                                    vecNewNodes[ 2 ]->second.back()));
-          srcElements.Append( myLastCreatedElems.Last() );
+          srcElements.Append( elem );
         }
       }
     }
@@ -4108,19 +4894,20 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
-        // check if a link is free
-        if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
+        // check if a link n1-n2 is free
+        if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
           hasFreeLinks = true;
-          // make an edge and a ceiling for a new edge
-          if ( !aMesh->FindEdge( n1, n2 )) {
-            myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
+          // make a new edge and a ceiling for a new edge
+          const SMDS_MeshElement* edge;
+          if ( ! ( edge = aMesh->FindEdge( n1, n2 ))) {
+            myLastCreatedElems.Append( edge = aMesh->AddEdge( n1, n2 )); // free link edge
             srcElements.Append( myLastCreatedElems.Last() );
           }
           n1 = vecNewNodes[ iNode ]->second.back();
           n2 = vecNewNodes[ iNext ]->second.back();
           if ( !aMesh->FindEdge( n1, n2 )) {
-            myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
-            srcElements.Append( myLastCreatedElems.Last() );
+            myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling
+            srcElements.Append( edge );
           }
         }
       }
@@ -4134,22 +4921,22 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
         // check if a link is free
-        if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
-             ! SMESH_MeshEditor::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
-             ! SMESH_MeshEditor::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
+        if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
+             ! SMESH_MeshAlgos::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
+             ! SMESH_MeshAlgos::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
           hasFreeLinks = true;
           // make an edge and a ceiling for a new edge
           // find medium node
           if ( !aMesh->FindEdge( n1, n2, n3 )) {
             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
-            srcElements.Append( myLastCreatedElems.Last() );
+            srcElements.Append( elem );
           }
           n1 = vecNewNodes[ iNode ]->second.back();
           n2 = vecNewNodes[ iNext ]->second.back();
           n3 = vecNewNodes[ iNode+nbn ]->second.back();
           if ( !aMesh->FindEdge( n1, n2, n3 )) {
             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
-            srcElements.Append( myLastCreatedElems.Last() );
+            srcElements.Append( elem );
           }
         }
       }
@@ -4160,15 +4947,20 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
 
     // sweep free links into faces
 
-    if ( hasFreeLinks )  {
+    if ( hasFreeLinks ) {
       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
 
       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
+      set<const SMDS_MeshNode*> initNodeSetNoCenter/*, topNodeSetNoCenter*/;
       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
         initNodeSet.insert( vecNewNodes[ iNode ]->first );
         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
       }
+      if ( isQuadratic && nbNodes % 2 ) {  // node set for the case of a biquadratic
+        initNodeSetNoCenter = initNodeSet; // swept face and a not biquadratic volume
+        initNodeSetNoCenter.erase( vecNewNodes.back()->first );
+      }
       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
         std::advance( v, volNb );
@@ -4184,14 +4976,17 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
           {
             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
               continue;
+            if ( faceNodeSet == initNodeSetNoCenter )
+              continue;
             freeInd.push_back( iF );
             // find source edge of a free face iF
             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
-            commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
-            std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
-                                   initNodeSet.begin(), initNodeSet.end(),
-                                   commonNodes.begin());
-            if ( (*v)->IsQuadratic() )
+            vector<const SMDS_MeshNode*>::iterator lastCommom;
+            commonNodes.resize( nbNodes, 0 );
+            lastCommom = std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
+                                                initNodeSet.begin(), initNodeSet.end(),
+                                                commonNodes.begin());
+            if ( std::distance( commonNodes.begin(), lastCommom ) == 3 )
               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
             else
               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
@@ -4207,10 +5002,11 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
         if ( freeInd.empty() )
           continue;
 
-        // create faces for all steps;
+        // create wall faces for all steps;
         // if such a face has been already created by sweep of edge,
         // assure that its orientation is OK
-        for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
+        for ( int iStep = 0; iStep < nbSteps; iStep++ )
+        {
           vTool.Set( *v, /*ignoreCentralNodes=*/false );
           vTool.SetExternalNormal();
           const int nextShift = vTool.IsForward() ? +1 : -1;
@@ -4337,7 +5133,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
                 if ( f )
                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
                 else
-                  AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
+                  AddElement( polygon_nodes, polyFace.SetQuad( (*v)->IsQuadratic() ));
               }
             }
 
@@ -4356,56 +5152,33 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
 
     // Make a ceiling face with a normal external to a volume
 
+    // use SMDS_VolumeTool to get a correctly ordered nodes of a ceiling face
     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
-
     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
-    if ( iF >= 0 ) {
+
+    if ( iF < 0 && isQuadratic && nbNodes % 2 ) { // remove a central node of biquadratic
+      aFaceLastNodes.erase( vecNewNodes.back()->second.back() );
+      iF = lastVol.GetFaceIndex( aFaceLastNodes );
+    }
+    if ( iF >= 0 )
+    {
       lastVol.SetExternalNormal();
       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
-      int nbn = lastVol.NbFaceNodes( iF );
-      if ( nbn == 3 ) {
-        if (!hasFreeLinks ||
-            !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
-          myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
-      }
-      else if ( nbn == 4 )
-      {
-        if (!hasFreeLinks ||
-            !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
-          myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]));
-      }
-      else if ( nbn == 6 && isQuadratic )
-      {
-        if (!hasFreeLinks ||
-            !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5]) )
-          myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
-                                                   nodes[1], nodes[3], nodes[5]));
-      }
-      else if ( nbn == 8 && isQuadratic )
-      {
-        if (!hasFreeLinks ||
-            !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
-                             nodes[1], nodes[3], nodes[5], nodes[7]) )
-          myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
-                                                   nodes[1], nodes[3], nodes[5], nodes[7]));
-      }
-      else if ( nbn == 9 && isQuadratic )
+      const               int nbn = lastVol.NbFaceNodes( iF );
+      vector<const SMDS_MeshNode*> nodeVec( nodes, nodes+nbn );
+      if ( !hasFreeLinks ||
+           !aMesh->FindElement( nodeVec, SMDSAbs_Face, /*noMedium=*/false) )
       {
-        if (!hasFreeLinks ||
-            !aMesh->FindElement(vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
-                                SMDSAbs_Face, /*noMedium=*/false) )
-          myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
-                                                   nodes[1], nodes[3], nodes[5], nodes[7],
-                                                   nodes[8]));
-      }
-      else {
-        vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes + nbn );
-        if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
-          myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
-      }
+        const vector<int>& interlace =
+          SMDS_MeshCell::interlacedSmdsOrder( elem->GetEntityType(), nbn );
+        SMDS_MeshCell::applyInterlaceRev( interlace, nodeVec );
+
+        if ( const SMDS_MeshElement* face = AddElement( nodeVec, anyFace.Init( elem )))
+          myLastCreatedElems.Append( face );
 
-      while ( srcElements.Length() < myLastCreatedElems.Length() )
-        srcElements.Append( myLastCreatedElems.Last() );
+        while ( srcElements.Length() < myLastCreatedElems.Length() )
+          srcElements.Append( elem );
+      }
     }
   } // loop on swept elements
 }
@@ -4416,7 +5189,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
 //=======================================================================
 
 SMESH_MeshEditor::PGroupIDs
-SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
+SMESH_MeshEditor::RotationSweep(TIDSortedElemSet   theElemSets[2],
                                 const gp_Ax1&      theAxis,
                                 const double       theAngle,
                                 const int          theNbSteps,
@@ -4443,89 +5216,94 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
 
   TNodeOfNodeListMap mapNewNodes;
   TElemOfVecOfNnlmiMap mapElemNewNodes;
-  TElemOfElemListMap newElemsMap;
+  TTElemOfElemListMap newElemsMap;
 
   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
                                      myMesh->NbFaces(ORDER_QUADRATIC) +
                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
-  // loop on theElems
+  // loop on theElemSets
+  setElemsFirst( theElemSets );
   TIDSortedElemSet::iterator itElem;
-  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
-    const SMDS_MeshElement* elem = *itElem;
-    if ( !elem || elem->GetType() == SMDSAbs_Volume )
-      continue;
-    vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
-    newNodesItVec.reserve( elem->NbNodes() );
+  for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
+  {
+    TIDSortedElemSet& theElems = theElemSets[ is2ndSet ];
+    for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+      const SMDS_MeshElement* elem = *itElem;
+      if ( !elem || elem->GetType() == SMDSAbs_Volume )
+        continue;
+      vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
+      newNodesItVec.reserve( elem->NbNodes() );
 
-    // loop on elem nodes
-    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-    while ( itN->more() )
-    {
-      // check if a node has been already sweeped
-      const SMDS_MeshNode* node = cast2Node( itN->next() );
+      // loop on elem nodes
+      SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+      while ( itN->more() )
+      {
+        const SMDS_MeshNode* node = cast2Node( itN->next() );
 
-      gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
-      double coord[3];
-      aXYZ.Coord( coord[0], coord[1], coord[2] );
-      bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
+        gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
+        double coord[3];
+        aXYZ.Coord( coord[0], coord[1], coord[2] );
+        bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
 
-      TNodeOfNodeListMapItr nIt =
-        mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
-      list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
-      if ( listNewNodes.empty() )
-      {
-        // check if we are to create medium nodes between corner ones
-        bool needMediumNodes = false;
-        if ( isQuadraticMesh )
+        // check if a node has been already sweeped
+        TNodeOfNodeListMapItr nIt =
+          mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
+        list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
+        if ( listNewNodes.empty() )
         {
-          SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
-          while (it->more() && !needMediumNodes )
+          // check if we are to create medium nodes between corner ones
+          bool needMediumNodes = false;
+          if ( isQuadraticMesh )
           {
-            const SMDS_MeshElement* invElem = it->next();
-            if ( invElem != elem && !theElems.count( invElem )) continue;
-            needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
-            if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
-              needMediumNodes = true;
+            SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
+            while (it->more() && !needMediumNodes )
+            {
+              const SMDS_MeshElement* invElem = it->next();
+              if ( invElem != elem && !theElems.count( invElem )) continue;
+              needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
+              if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
+                needMediumNodes = true;
+            }
           }
-        }
 
-        // make new nodes
-        const SMDS_MeshNode * newNode = node;
-        for ( int i = 0; i < theNbSteps; i++ ) {
-          if ( !isOnAxis ) {
-            if ( needMediumNodes )  // create a medium node
-            {
-              aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+          // make new nodes
+          const SMDS_MeshNode * newNode = node;
+          for ( int i = 0; i < theNbSteps; i++ ) {
+            if ( !isOnAxis ) {
+              if ( needMediumNodes )  // create a medium node
+              {
+                aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+                newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+                myLastCreatedNodes.Append(newNode);
+                srcNodes.Append( node );
+                listNewNodes.push_back( newNode );
+                aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+              }
+              else {
+                aTrsf.Transforms( coord[0], coord[1], coord[2] );
+              }
+              // create a corner node
               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
               myLastCreatedNodes.Append(newNode);
               srcNodes.Append( node );
               listNewNodes.push_back( newNode );
-              aTrsf2.Transforms( coord[0], coord[1], coord[2] );
             }
             else {
-              aTrsf.Transforms( coord[0], coord[1], coord[2] );
+              listNewNodes.push_back( newNode );
+              // if ( needMediumNodes )
+              //   listNewNodes.push_back( newNode );
             }
-            // create a corner node
-            newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
-            myLastCreatedNodes.Append(newNode);
-            srcNodes.Append( node );
-            listNewNodes.push_back( newNode );
-          }
-          else {
-            listNewNodes.push_back( newNode );
-            // if ( needMediumNodes )
-            //   listNewNodes.push_back( newNode );
           }
         }
+        newNodesItVec.push_back( nIt );
       }
-      newNodesItVec.push_back( nIt );
+      // make new elements
+      sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
     }
-    // make new elements
-    sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
   }
 
   if ( theMakeWalls )
-    makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
+    makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], theNbSteps, srcElems );
 
   PGroupIDs newGroupIDs;
   if ( theMakeGroups )
@@ -4534,50 +5312,328 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
   return newGroupIDs;
 }
 
+//=======================================================================
+//function : ExtrusParam
+//purpose  : standard construction
+//=======================================================================
+
+SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Vec&  theStep,
+                                            const int      theNbSteps,
+                                            const int      theFlags,
+                                            const double   theTolerance):
+  myDir( theStep ),
+  myFlags( theFlags ),
+  myTolerance( theTolerance ),
+  myElemsToUse( NULL )
+{
+  mySteps = new TColStd_HSequenceOfReal;
+  const double stepSize = theStep.Magnitude();
+  for (int i=1; i<=theNbSteps; i++ )
+    mySteps->Append( stepSize );
+
+  if (( theFlags & EXTRUSION_FLAG_SEW ) &&
+      ( theTolerance > 0 ))
+  {
+    myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDirAndSew;
+  }
+  else
+  {
+    myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDir;
+  }
+}
 
 //=======================================================================
-//function : CreateNode
-//purpose  :
+//function : ExtrusParam
+//purpose  : steps are given explicitly
+//=======================================================================
+
+SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Dir&                   theDir,
+                                            Handle(TColStd_HSequenceOfReal) theSteps,
+                                            const int                       theFlags,
+                                            const double                    theTolerance):
+  myDir( theDir ),
+  mySteps( theSteps ),
+  myFlags( theFlags ),
+  myTolerance( theTolerance ),
+  myElemsToUse( NULL )
+{
+  if (( theFlags & EXTRUSION_FLAG_SEW ) &&
+      ( theTolerance > 0 ))
+  {
+    myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDirAndSew;
+  }
+  else
+  {
+    myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDir;
+  }
+}
+
+//=======================================================================
+//function : ExtrusParam
+//purpose  : for extrusion by normal
+//=======================================================================
+
+SMESH_MeshEditor::ExtrusParam::ExtrusParam( const double theStepSize,
+                                            const int    theNbSteps,
+                                            const int    theFlags,
+                                            const int    theDim ):
+  myDir( 1,0,0 ),
+  mySteps( new TColStd_HSequenceOfReal ),
+  myFlags( theFlags ),
+  myTolerance( 0 ),
+  myElemsToUse( NULL )
+{
+  for (int i = 0; i < theNbSteps; i++ )
+    mySteps->Append( theStepSize );
+
+  if ( theDim == 1 )
+  {
+    myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByNormal1D;
+  }
+  else
+  {
+    myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByNormal2D;
+  }
+}
+
+//=======================================================================
+//function : ExtrusParam::SetElementsToUse
+//purpose  : stores elements to use for extrusion by normal, depending on
+//           state of EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY flag
+//=======================================================================
+
+void SMESH_MeshEditor::ExtrusParam::SetElementsToUse( const TIDSortedElemSet& elems )
+{
+  myElemsToUse = ToUseInpElemsOnly() ? & elems : 0;
+}
+
 //=======================================================================
-const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
-                                                  const double y,
-                                                  const double z,
-                                                  const double tolnode,
-                                                  SMESH_SequenceOfNode& aNodes)
+//function : ExtrusParam::beginStepIter
+//purpose  : prepare iteration on steps
+//=======================================================================
+
+void SMESH_MeshEditor::ExtrusParam::beginStepIter( bool withMediumNodes )
 {
-  // myLastCreatedElems.Clear();
-  // myLastCreatedNodes.Clear();
+  myWithMediumNodes = withMediumNodes;
+  myNextStep = 1;
+  myCurSteps.clear();
+}
+//=======================================================================
+//function : ExtrusParam::moreSteps
+//purpose  : are there more steps?
+//=======================================================================
 
-  gp_Pnt P1(x,y,z);
-  SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
+bool SMESH_MeshEditor::ExtrusParam::moreSteps()
+{
+  return myNextStep <= mySteps->Length() || !myCurSteps.empty();
+}
+//=======================================================================
+//function : ExtrusParam::nextStep
+//purpose  : returns the next step
+//=======================================================================
 
-  // try to search in sequence of existing nodes
-  // if aNodes.Length()>0 we 'nave to use given sequence
-  // else - use all nodes of mesh
-  if(aNodes.Length()>0) {
-    int i;
-    for(i=1; i<=aNodes.Length(); i++) {
-      gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
-      if(P1.Distance(P2)<tolnode)
-        return aNodes.Value(i);
+double SMESH_MeshEditor::ExtrusParam::nextStep()
+{
+  double res = 0;
+  if ( !myCurSteps.empty() )
+  {
+    res = myCurSteps.back();
+    myCurSteps.pop_back();
+  }
+  else if ( myNextStep <= mySteps->Length() )
+  {
+    myCurSteps.push_back( mySteps->Value( myNextStep ));
+    ++myNextStep;
+    if ( myWithMediumNodes )
+    {
+      myCurSteps.back() /= 2.;
+      myCurSteps.push_back( myCurSteps.back() );
     }
+    res = nextStep();
   }
-  else {
-    SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
-    while(itn->more()) {
-      const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
-      gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
-      if(P1.Distance(P2)<tolnode)
-        return aN;
+  return res;
+}
+
+//=======================================================================
+//function : ExtrusParam::makeNodesByDir
+//purpose  : create nodes for standard extrusion
+//=======================================================================
+
+int SMESH_MeshEditor::ExtrusParam::
+makeNodesByDir( SMESHDS_Mesh*                     mesh,
+                const SMDS_MeshNode*              srcNode,
+                std::list<const SMDS_MeshNode*> & newNodes,
+                const bool                        makeMediumNodes)
+{
+  gp_XYZ p = SMESH_TNodeXYZ( srcNode );
+
+  int nbNodes = 0;
+  for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps
+  {
+    p += myDir.XYZ() * nextStep();
+    const SMDS_MeshNode * newNode = mesh->AddNode( p.X(), p.Y(), p.Z() );
+    newNodes.push_back( newNode );
+  }
+  return nbNodes;
+}
+
+//=======================================================================
+//function : ExtrusParam::makeNodesByDirAndSew
+//purpose  : create nodes for standard extrusion with sewing
+//=======================================================================
+
+int SMESH_MeshEditor::ExtrusParam::
+makeNodesByDirAndSew( SMESHDS_Mesh*                     mesh,
+                      const SMDS_MeshNode*              srcNode,
+                      std::list<const SMDS_MeshNode*> & newNodes,
+                      const bool                        makeMediumNodes)
+{
+  gp_XYZ P1 = SMESH_TNodeXYZ( srcNode );
+
+  int nbNodes = 0;
+  for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps
+  {
+    P1 += myDir.XYZ() * nextStep();
+
+    // try to search in sequence of existing nodes
+    // if myNodes.Length()>0 we 'nave to use given sequence
+    // else - use all nodes of mesh
+    const SMDS_MeshNode * node = 0;
+    if ( myNodes.Length() > 0 ) {
+      int i;
+      for(i=1; i<=myNodes.Length(); i++) {
+        gp_XYZ P2 = SMESH_TNodeXYZ( myNodes.Value(i) );
+        if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance )
+        {
+          node = myNodes.Value(i);
+          break;
+        }
+      }
+    }
+    else {
+      SMDS_NodeIteratorPtr itn = mesh->nodesIterator();
+      while(itn->more()) {
+        SMESH_TNodeXYZ P2( itn->next() );
+        if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance )
+        {
+          node = P2._node;
+          break;
+        }
+      }
+    }
+
+    if ( !node )
+      node = mesh->AddNode( P1.X(), P1.Y(), P1.Z() );
+
+    newNodes.push_back( node );
+
+  } // loop on steps
+
+  return nbNodes;
+}
+
+//=======================================================================
+//function : ExtrusParam::makeNodesByNormal2D
+//purpose  : create nodes for extrusion using normals of faces
+//=======================================================================
+
+int SMESH_MeshEditor::ExtrusParam::
+makeNodesByNormal2D( SMESHDS_Mesh*                     mesh,
+                     const SMDS_MeshNode*              srcNode,
+                     std::list<const SMDS_MeshNode*> & newNodes,
+                     const bool                        makeMediumNodes)
+{
+  const bool alongAvgNorm = ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL );
+
+  gp_XYZ p = SMESH_TNodeXYZ( srcNode );
+
+  // get normals to faces sharing srcNode
+  vector< gp_XYZ > norms, baryCenters;
+  gp_XYZ norm, avgNorm( 0,0,0 );
+  SMDS_ElemIteratorPtr faceIt = srcNode->GetInverseElementIterator( SMDSAbs_Face );
+  while ( faceIt->more() )
+  {
+    const SMDS_MeshElement* face = faceIt->next();
+    if ( myElemsToUse && !myElemsToUse->count( face ))
+      continue;
+    if ( SMESH_MeshAlgos::FaceNormal( face, norm, /*normalized=*/true ))
+    {
+      norms.push_back( norm );
+      avgNorm += norm;
+      if ( !alongAvgNorm )
+      {
+        gp_XYZ bc(0,0,0);
+        int nbN = 0;
+        for ( SMDS_ElemIteratorPtr nIt = face->nodesIterator(); nIt->more(); ++nbN )
+          bc += SMESH_TNodeXYZ( nIt->next() );
+        baryCenters.push_back( bc / nbN );
+      }
     }
   }
 
-  // create new node and return it
-  const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
-  //myLastCreatedNodes.Append(NewNode);
-  return NewNode;
+  if ( norms.empty() ) return 0;
+
+  double normSize = avgNorm.Modulus();
+  if ( normSize < std::numeric_limits<double>::min() )
+    return 0;
+
+  if ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL ) // extrude along avgNorm
+  {
+    myDir = avgNorm;
+    return makeNodesByDir( mesh, srcNode, newNodes, makeMediumNodes );
+  }
+
+  avgNorm /= normSize;
+
+  int nbNodes = 0;
+  for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps
+  {
+    gp_XYZ pNew = p;
+    double stepSize = nextStep();
+
+    if ( norms.size() > 1 )
+    {
+      for ( size_t iF = 0; iF < norms.size(); ++iF ) // loop on faces
+      {
+        // translate plane of a face
+        baryCenters[ iF ] += norms[ iF ] * stepSize;
+
+        // find point of intersection of the face plane located at baryCenters[ iF ]
+        // and avgNorm located at pNew
+        double d    = -( norms[ iF ] * baryCenters[ iF ]); // d of plane equation ax+by+cz+d=0
+        double dot  = ( norms[ iF ] * avgNorm );
+        if ( dot < std::numeric_limits<double>::min() )
+          dot = stepSize * 1e-3;
+        double step = -( norms[ iF ] * pNew + d ) / dot;
+        pNew += step * avgNorm;
+      }
+    }
+    else
+    {
+      pNew += stepSize * avgNorm;
+    }
+    p = pNew;
+
+    const SMDS_MeshNode * newNode = mesh->AddNode( p.X(), p.Y(), p.Z() );
+    newNodes.push_back( newNode );
+  }
+  return nbNodes;
 }
 
+//=======================================================================
+//function : ExtrusParam::makeNodesByNormal1D
+//purpose  : create nodes for extrusion using normals of edges
+//=======================================================================
+
+int SMESH_MeshEditor::ExtrusParam::
+makeNodesByNormal1D( SMESHDS_Mesh*                     mesh,
+                     const SMDS_MeshNode*              srcNode,
+                     std::list<const SMDS_MeshNode*> & newNodes,
+                     const bool                        makeMediumNodes)
+{
+  throw SALOME_Exception("Extrusion 1D by Normal not implemented");
+  return 0;
+}
 
 //=======================================================================
 //function : ExtrusionSweep
@@ -4585,24 +5641,15 @@ const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
 //=======================================================================
 
 SMESH_MeshEditor::PGroupIDs
-SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
-                                  const gp_Vec&       theStep,
-                                  const int           theNbSteps,
-                                  TElemOfElemListMap& newElemsMap,
-                                  const bool          theMakeGroups,
-                                  const int           theFlags,
-                                  const double        theTolerance)
+SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet     theElems[2],
+                                  const gp_Vec&        theStep,
+                                  const int            theNbSteps,
+                                  TTElemOfElemListMap& newElemsMap,
+                                  const int            theFlags,
+                                  const double         theTolerance)
 {
-  ExtrusParam aParams;
-  aParams.myDir = gp_Dir(theStep);
-  aParams.myNodes.Clear();
-  aParams.mySteps = new TColStd_HSequenceOfReal;
-  int i;
-  for(i=1; i<=theNbSteps; i++)
-    aParams.mySteps->Append(theStep.Magnitude());
-
-  return
-    ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
+  ExtrusParam aParams( theStep, theNbSteps, theFlags, theTolerance );
+  return ExtrusionSweep( theElems, aParams, newElemsMap );
 }
 
 
@@ -4612,12 +5659,9 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
 //=======================================================================
 
 SMESH_MeshEditor::PGroupIDs
-SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
-                                  ExtrusParam&        theParams,
-                                  TElemOfElemListMap& newElemsMap,
-                                  const bool          theMakeGroups,
-                                  const int           theFlags,
-                                  const double        theTolerance)
+SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet     theElemSets[2],
+                                  ExtrusParam&         theParams,
+                                  TTElemOfElemListMap& newElemsMap)
 {
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
@@ -4627,7 +5671,9 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
 
   SMESHDS_Mesh* aMesh = GetMeshDS();
 
-  int nbsteps = theParams.mySteps->Length();
+  setElemsFirst( theElemSets );
+  const int nbSteps = theParams.NbSteps();
+  theParams.SetElementsToUse( theElemSets[0] );
 
   TNodeOfNodeListMap mapNewNodes;
   //TNodeOfNodeVecMap mapNewNodes;
@@ -4639,91 +5685,75 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
   // loop on theElems
   TIDSortedElemSet::iterator itElem;
-  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
-    // check element type
-    const SMDS_MeshElement* elem = *itElem;
-    if ( !elem  || elem->GetType() == SMDSAbs_Volume )
-      continue;
+  for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
+  {
+    TIDSortedElemSet& theElems = theElemSets[ is2ndSet ];
+    for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
+    {
+      // check element type
+      const SMDS_MeshElement* elem = *itElem;
+      if ( !elem  || elem->GetType() == SMDSAbs_Volume )
+        continue;
 
-    vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
-    newNodesItVec.reserve( elem->NbNodes() );
+      const size_t nbNodes = elem->NbNodes();
+      vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
+      newNodesItVec.reserve( nbNodes );
 
-    // loop on elem nodes
-    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-    while ( itN->more() )
-    {
-      // check if a node has been already sweeped
-      const SMDS_MeshNode* node = cast2Node( itN->next() );
-      TNodeOfNodeListMap::iterator nIt =
-        mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
-      list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
-      if ( listNewNodes.empty() )
+      // loop on elem nodes
+      SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+      while ( itN->more() )
       {
-        // make new nodes
-
-        // check if we are to create medium nodes between corner ones
-        bool needMediumNodes = false;
-        if ( isQuadraticMesh )
+        // check if a node has been already sweeped
+        const SMDS_MeshNode* node = cast2Node( itN->next() );
+        TNodeOfNodeListMap::iterator nIt =
+          mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
+        list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
+        if ( listNewNodes.empty() )
         {
-          SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
-          while (it->more() && !needMediumNodes )
-          {
-            const SMDS_MeshElement* invElem = it->next();
-            if ( invElem != elem && !theElems.count( invElem )) continue;
-            needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
-            if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
-              needMediumNodes = true;
-          }
-        }
+          // make new nodes
 
-        double coord[] = { node->X(), node->Y(), node->Z() };
-        for ( int i = 0; i < nbsteps; i++ )
-        {
-          if ( needMediumNodes ) // create a medium node
+          // check if we are to create medium nodes between corner ones
+          bool needMediumNodes = false;
+          if ( isQuadraticMesh )
           {
-            double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
-            double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
-            double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
-            if( theFlags & EXTRUSION_FLAG_SEW ) {
-              const SMDS_MeshNode * newNode = CreateNode(x, y, z,
-                                                         theTolerance, theParams.myNodes);
-              listNewNodes.push_back( newNode );
+            SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
+            while (it->more() && !needMediumNodes )
+            {
+              const SMDS_MeshElement* invElem = it->next();
+              if ( invElem != elem && !theElems.count( invElem )) continue;
+              needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
+              if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
+                needMediumNodes = true;
             }
-            else {
-              const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
-              myLastCreatedNodes.Append(newNode);
+          }
+          // create nodes for all steps
+          if ( theParams.MakeNodes( GetMeshDS(), node, listNewNodes, needMediumNodes ))
+          {
+            list<const SMDS_MeshNode*>::iterator newNodesIt = listNewNodes.begin();
+            for ( ; newNodesIt != listNewNodes.end(); ++newNodesIt )
+            {
+              myLastCreatedNodes.Append( *newNodesIt );
               srcNodes.Append( node );
-              listNewNodes.push_back( newNode );
             }
           }
-          // create a corner node
-          coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
-          coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
-          coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
-          if( theFlags & EXTRUSION_FLAG_SEW ) {
-            const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
-                                                       theTolerance, theParams.myNodes);
-            listNewNodes.push_back( newNode );
-          }
-          else {
-            const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
-            myLastCreatedNodes.Append(newNode);
-            srcNodes.Append( node );
-            listNewNodes.push_back( newNode );
+          else
+          {
+            break; // newNodesItVec will be shorter than nbNodes
           }
         }
+        newNodesItVec.push_back( nIt );
       }
-      newNodesItVec.push_back( nIt );
+      // make new elements
+      if ( newNodesItVec.size() == nbNodes )
+        sweepElement( elem, newNodesItVec, newElemsMap[elem], nbSteps, srcElems );
     }
-    // make new elements
-    sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
   }
 
-  if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
-    makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
+  if ( theParams.ToMakeBoundary() ) {
+    makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], nbSteps, srcElems );
   }
   PGroupIDs newGroupIDs;
-  if ( theMakeGroups )
+  if ( theParams.ToMakeGroups() )
     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
 
   return newGroupIDs;
@@ -4734,7 +5764,7 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
 //purpose  :
 //=======================================================================
 SMESH_MeshEditor::Extrusion_Error
-SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
+SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet     theElements[2],
                                        SMESH_subMesh*       theTrack,
                                        const SMDS_MeshNode* theN1,
                                        const bool           theHasAngles,
@@ -4763,7 +5793,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
   TNodeOfNodeListMap mapNewNodes;
 
   // 1. Check data
-  aNbE = theElements.size();
+  aNbE = theElements[0].size() + theElements[1].size();
   // nothing to do
   if ( !aNbE )
     return EXTR_NO_ELEMENTS;
@@ -4789,7 +5819,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
   if( aS.ShapeType() == TopAbs_EDGE ) {
     aTrackEdge = TopoDS::Edge( aS );
     // the Edge must not be degenerated
-    if ( BRep_Tool::Degenerated( aTrackEdge ) )
+    if ( SMESH_Algo::isDegenerated( aTrackEdge ) )
       return EXTR_BAD_PATH_SHAPE;
     TopExp::Vertices( aTrackEdge, aV1, aV2 );
     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
@@ -4822,7 +5852,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
     int startNid = theN1->GetID();
     TColStd_MapOfInteger UsedNums;
-    
+
     int NbEdges = Edges.Length();
     int i = 1;
     for(; i<=NbEdges; i++) {
@@ -4906,7 +5936,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
 //purpose  :
 //=======================================================================
 SMESH_MeshEditor::Extrusion_Error
-SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
+SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet     theElements[2],
                                        SMESH_Mesh*          theTrack,
                                        const SMDS_MeshNode* theN1,
                                        const bool           theHasAngles,
@@ -4934,7 +5964,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
   TNodeOfNodeListMap mapNewNodes;
 
   // 1. Check data
-  aNbE = theElements.size();
+  aNbE = theElements[0].size() + theElements[1].size();
   // nothing to do
   if ( !aNbE )
     return EXTR_NO_ELEMENTS;
@@ -4957,7 +5987,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
 
   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
 
-  if( aS == SMESH_Mesh::PseudoShape() ) {
+  if ( !theTrack->HasShapeToMesh() ) {
     //Mesh without shape
     const SMDS_MeshNode* currentNode = NULL;
     const SMDS_MeshNode* prevNode = theN1;
@@ -4973,9 +6003,9 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
       return EXTR_BAD_STARTING_NODE;
     }
-    
+
     conn = nbEdgeConnectivity(theN1);
-    if(conn > 2)
+    if( conn != 1 )
       return EXTR_PATH_NOT_EDGE;
 
     aItE = theN1->GetInverseElementIterator();
@@ -4988,14 +6018,14 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
       if(currentNode == prevNode)
         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
       aNodesList.push_back(currentNode);
-    } else { 
+    } else {
       nIt = currentElem->nodesIterator();
       while( nIt->more() ) {
         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
         if(currentNode == prevNode)
           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
         aNodesList.push_back(currentNode);
-        
+
         //case of the closed mesh
         if(currentNode == theN1) {
           nbEdges++;
@@ -5004,7 +6034,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
 
         conn = nbEdgeConnectivity(currentNode);
         if(conn > 2) {
-          return EXTR_PATH_NOT_EDGE;    
+          return EXTR_PATH_NOT_EDGE;
         }else if( conn == 1 && nbEdges > 0 ) {
           //End of the path
           nbEdges++;
@@ -5020,8 +6050,8 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
           nbEdges++;
         }
       }
-    } 
-    
+    }
+
     if(nbEdges != totalNbEdges)
       return EXTR_PATH_NOT_EDGE;
 
@@ -5033,7 +6063,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
-      TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));  
+      TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));
       list<SMESH_MeshEditor_PathPoint> LPP;
       aPrms.clear();
       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
@@ -5072,18 +6102,16 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
       fullList.pop_back();
     }
     fullList.push_back(PP1);
-    
+
   } // Sub-shape for the Pattern must be an Edge or Wire
   else if( aS.ShapeType() == TopAbs_EDGE ) {
     aTrackEdge = TopoDS::Edge( aS );
     // the Edge must not be degenerated
-    if ( BRep_Tool::Degenerated( aTrackEdge ) )
+    if ( SMESH_Algo::isDegenerated( aTrackEdge ) )
       return EXTR_BAD_PATH_SHAPE;
     TopExp::Vertices( aTrackEdge, aV1, aV2 );
-    aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
-    const SMDS_MeshNode* aN1 = aItN->next();
-    aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
-    const SMDS_MeshNode* aN2 = aItN->next();
+    const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS );
+    const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS );
     // starting node must be aN1 or aN2
     if ( !( aN1 == theN1 || aN2 == theN1 ) )
       return EXTR_BAD_STARTING_NODE;
@@ -5105,7 +6133,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
     TopExp_Explorer eExp(aS, TopAbs_EDGE);
     for(; eExp.More(); eExp.Next()) {
       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
-      if( BRep_Tool::Degenerated(E) ) continue;
+      if( SMESH_Algo::isDegenerated(E) ) continue;
       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
       if(SM) {
         LSM.push_back(SM);
@@ -5113,7 +6141,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
       }
     }
     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
-    int startNid = theN1->GetID();
+    TopoDS_Vertex aVprev;
     TColStd_MapOfInteger UsedNums;
     int NbEdges = Edges.Length();
     int i = 1;
@@ -5127,17 +6155,28 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
         SMESH_subMesh* locTrack = *itLSM;
         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
         TopExp::Vertices( aTrackEdge, aV1, aV2 );
-        aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
-        const SMDS_MeshNode* aN1 = aItN->next();
-        aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
-        const SMDS_MeshNode* aN2 = aItN->next();
-        // starting node must be aN1 or aN2
-        if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
+        bool aN1isOK = false, aN2isOK = false;
+        if ( aVprev.IsNull() ) {
+          // if previous vertex is not yet defined, it means that we in the beginning of wire
+          // and we have to find initial vertex corresponding to starting node theN1
+          const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS );
+          const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS );
+          // starting node must be aN1 or aN2
+          aN1isOK = ( aN1 && aN1 == theN1 );
+          aN2isOK = ( aN2 && aN2 == theN1 );
+        }
+        else {
+          // we have specified ending vertex of the previous edge on the previous iteration
+          // and we have just to check that it corresponds to any vertex in current segment
+          aN1isOK = aVprev.IsSame( aV1 );
+          aN2isOK = aVprev.IsSame( aV2 );
+        }
+        if ( !aN1isOK && !aN2isOK ) continue;
         // 2. Collect parameters on the track edge
         aPrms.clear();
         aItN = locMeshDS->GetNodes();
         while ( aItN->more() ) {
-          const SMDS_MeshNode* pNode = aItN->next();
+          const SMDS_MeshNode*     pNode = aItN->next();
           const SMDS_EdgePosition* pEPos =
             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
           double aT = pEPos->GetUParameter();
@@ -5145,38 +6184,31 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
         }
         list<SMESH_MeshEditor_PathPoint> LPP;
         //Extrusion_Error err =
-        MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
+        MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
         LLPPs.push_back(LPP);
         UsedNums.Add(k);
         // update startN for search following egde
-        if( aN1->GetID() == startNid ) startNid = aN2->GetID();
-        else startNid = aN1->GetID();
+        if ( aN1isOK ) aVprev = aV2;
+        else           aVprev = aV1;
         break;
       }
     }
     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
-    list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
-    list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
-    for(; itPP!=firstList.end(); itPP++) {
-      fullList.push_back( *itPP );
-    }
+    list<SMESH_MeshEditor_PathPoint>& firstList = *itLLPP;
+    fullList.splice( fullList.end(), firstList );
+
     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
     fullList.pop_back();
     itLLPP++;
     for(; itLLPP!=LLPPs.end(); itLLPP++) {
-      list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
-      itPP = currList.begin();
+      list<SMESH_MeshEditor_PathPoint>& currList = *itLLPP;
       SMESH_MeshEditor_PathPoint PP2 = currList.front();
       gp_Dir D1 = PP1.Tangent();
       gp_Dir D2 = PP2.Tangent();
-      gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
-                           (D1.Z()+D2.Z())/2 ) );
+      gp_Dir Dnew( ( D1.XYZ() + D2.XYZ() ) / 2 );
       PP1.SetTangent(Dnew);
       fullList.push_back(PP1);
-      itPP++;
-      for(; itPP!=currList.end(); itPP++) {
-        fullList.push_back( *itPP );
-      }
+      fullList.splice( fullList.end(), currList, ++currList.begin(), currList.end() );
       PP1 = fullList.back();
       fullList.pop_back();
     }
@@ -5198,9 +6230,9 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
 //purpose  : auxilary for ExtrusionAlongTrack
 //=======================================================================
 SMESH_MeshEditor::Extrusion_Error
-SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
-                                     const TopoDS_Edge& aTrackEdge,
-                                     bool FirstIsStart,
+SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>&                aPrms,
+                                     const TopoDS_Edge&                aTrackEdge,
+                                     bool                              FirstIsStart,
                                      list<SMESH_MeshEditor_PathPoint>& LPP)
 {
   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
@@ -5253,236 +6285,211 @@ SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
 //purpose  : auxilary for ExtrusionAlongTrack
 //=======================================================================
 SMESH_MeshEditor::Extrusion_Error
-SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
+SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet                  theElemSets[2],
                                    list<SMESH_MeshEditor_PathPoint>& fullList,
-                                   const bool theHasAngles,
-                                   list<double>& theAngles,
-                                   const bool theLinearVariation,
-                                   const bool theHasRefPoint,
-                                   const gp_Pnt& theRefPoint,
-                                   const bool theMakeGroups)
+                                   const bool                        theHasAngles,
+                                   list<double>&                     theAngles,
+                                   const bool                        theLinearVariation,
+                                   const bool                        theHasRefPoint,
+                                   const gp_Pnt&                     theRefPoint,
+                                   const bool                        theMakeGroups)
 {
-  MESSAGE("MakeExtrElements");
-  //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
-  int aNbTP = fullList.size();
-  vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
+  const int aNbTP = fullList.size();
   // Angles
-  if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
+  if( theHasAngles && !theAngles.empty() && theLinearVariation )
     LinearAngleVariation(aNbTP-1, theAngles);
-  }
-  vector<double> aAngles( aNbTP );
-  int j = 0;
-  for(; j<aNbTP; ++j) {
-    aAngles[j] = 0.;
-  }
-  if ( theHasAngles ) {
-    double anAngle;;
-    std::list<double>::iterator aItD = theAngles.begin();
-    for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
-      anAngle = *aItD;
-      aAngles[j] = anAngle;
-    }
-  }
   // fill vector of path points with angles
-  //aPPs.resize(fullList.size());
-  j = -1;
+  vector<SMESH_MeshEditor_PathPoint> aPPs;
   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
-  for(; itPP!=fullList.end(); itPP++) {
-    j++;
-    SMESH_MeshEditor_PathPoint PP = *itPP;
-    PP.SetAngle(aAngles[j]);
-    aPPs[j] = PP;
+  list<double>::iterator                 itAngles = theAngles.begin();
+  aPPs.push_back( *itPP++ );
+  for( ; itPP != fullList.end(); itPP++) {
+    aPPs.push_back( *itPP );
+    if ( theHasAngles && itAngles != theAngles.end() )
+      aPPs.back().SetAngle( *itAngles++ );
   }
 
-  TNodeOfNodeListMap mapNewNodes;
+  TNodeOfNodeListMap   mapNewNodes;
   TElemOfVecOfNnlmiMap mapElemNewNodes;
-  TElemOfElemListMap newElemsMap;
+  TTElemOfElemListMap  newElemsMap;
   TIDSortedElemSet::iterator itElem;
-  double aX, aY, aZ;
-  int aNb;
-  SMDSAbs_ElementType aTypeE;
   // source elements for each generated one
   SMESH_SequenceOfElemPtr srcElems, srcNodes;
 
   // 3. Center of rotation aV0
   gp_Pnt aV0 = theRefPoint;
-  gp_XYZ aGC;
-  if ( !theHasRefPoint ) {
-    aNb = 0;
-    aGC.SetCoord( 0.,0.,0. );
-
-    itElem = theElements.begin();
-    for ( ; itElem != theElements.end(); itElem++ ) {
-      const SMDS_MeshElement* elem = *itElem;
+  if ( !theHasRefPoint )
+  {
+    gp_XYZ aGC( 0.,0.,0. );
+    TIDSortedElemSet newNodes;
 
-      SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-      while ( itN->more() ) {
-        const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
-        aX = node->X();
-        aY = node->Y();
-        aZ = node->Z();
+    for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
+    {
+      TIDSortedElemSet& theElements = theElemSets[ is2ndSet ];
+      itElem = theElements.begin();
+      for ( ; itElem != theElements.end(); itElem++ ) {
+        const SMDS_MeshElement* elem = *itElem;
 
-        if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
-          list<const SMDS_MeshNode*> aLNx;
-          mapNewNodes[node] = aLNx;
-          //
-          gp_XYZ aXYZ( aX, aY, aZ );
-          aGC += aXYZ;
-          ++aNb;
+        SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+        while ( itN->more() ) {
+          const SMDS_MeshElement* node = itN->next();
+          if ( newNodes.insert( node ).second )
+            aGC += SMESH_TNodeXYZ( node );
         }
       }
     }
-    aGC /= aNb;
+    aGC /= newNodes.size();
     aV0.SetXYZ( aGC );
   } // if (!theHasRefPoint) {
-  mapNewNodes.clear();
 
   // 4. Processing the elements
   SMESHDS_Mesh* aMesh = GetMeshDS();
 
-  for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
-    // check element type
-    const SMDS_MeshElement* elem = *itElem;
-    aTypeE = elem->GetType();
-    if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
-      continue;
-
-    vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
-    newNodesItVec.reserve( elem->NbNodes() );
-
-    // loop on elem nodes
-    int nodeIndex = -1;
-    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-    while ( itN->more() )
-    {
-      ++nodeIndex;
-      // check if a node has been already processed
-      const SMDS_MeshNode* node =
-        static_cast<const SMDS_MeshNode*>( itN->next() );
-      TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
-      if ( nIt == mapNewNodes.end() ) {
-        nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
-        list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
-
-        // make new nodes
-        aX = node->X();  aY = node->Y(); aZ = node->Z();
-
-        Standard_Real aAngle1x, aAngleT1T0, aTolAng;
-        gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
-        gp_Ax1 anAx1, anAxT1T0;
-        gp_Dir aDT1x, aDT0x, aDT1T0;
-
-        aTolAng=1.e-4;
-
-        aV0x = aV0;
-        aPN0.SetCoord(aX, aY, aZ);
-
-        const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
-        aP0x = aPP0.Pnt();
-        aDT0x= aPP0.Tangent();
-        //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
-
-        for ( j = 1; j < aNbTP; ++j ) {
-          const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
-          aP1x = aPP1.Pnt();
-          aDT1x = aPP1.Tangent();
-          aAngle1x = aPP1.Angle();
-
-          gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
-          // Translation
-          gp_Vec aV01x( aP0x, aP1x );
-          aTrsf.SetTranslation( aV01x );
-
-          // traslated point
-          aV1x = aV0x.Transformed( aTrsf );
-          aPN1 = aPN0.Transformed( aTrsf );
+  setElemsFirst( theElemSets );
+  for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
+  {
+    TIDSortedElemSet& theElements = theElemSets[ is2ndSet ];
+    for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
+      // check element type
+      const SMDS_MeshElement* elem = *itElem;
+      if ( !elem )
+        continue;
+      // SMDSAbs_ElementType aTypeE = elem->GetType();
+      // if ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge )
+      //   continue;
 
-          // rotation 1 [ T1,T0 ]
-          aAngleT1T0=-aDT1x.Angle( aDT0x );
-          if (fabs(aAngleT1T0) > aTolAng) {
-            aDT1T0=aDT1x^aDT0x;
-            anAxT1T0.SetLocation( aV1x );
-            anAxT1T0.SetDirection( aDT1T0 );
-            aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
+      vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
+      newNodesItVec.reserve( elem->NbNodes() );
 
-            aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
-          }
+      // loop on elem nodes
+      int nodeIndex = -1;
+      SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+      while ( itN->more() )
+      {
+        ++nodeIndex;
+        // check if a node has been already processed
+        const SMDS_MeshNode* node =
+          static_cast<const SMDS_MeshNode*>( itN->next() );
+        TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
+        if ( nIt == mapNewNodes.end() ) {
+          nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
+          list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
+
+          // make new nodes
+          Standard_Real aAngle1x, aAngleT1T0, aTolAng;
+          gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
+          gp_Ax1 anAx1, anAxT1T0;
+          gp_Dir aDT1x, aDT0x, aDT1T0;
+
+          aTolAng=1.e-4;
+
+          aV0x = aV0;
+          aPN0 = SMESH_TNodeXYZ( node );
+
+          const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
+          aP0x = aPP0.Pnt();
+          aDT0x= aPP0.Tangent();
+          //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
+
+          for ( int j = 1; j < aNbTP; ++j ) {
+            const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
+            aP1x     = aPP1.Pnt();
+            aDT1x    = aPP1.Tangent();
+            aAngle1x = aPP1.Angle();
+
+            gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
+            // Translation
+            gp_Vec aV01x( aP0x, aP1x );
+            aTrsf.SetTranslation( aV01x );
+
+            // traslated point
+            aV1x = aV0x.Transformed( aTrsf );
+            aPN1 = aPN0.Transformed( aTrsf );
+
+            // rotation 1 [ T1,T0 ]
+            aAngleT1T0=-aDT1x.Angle( aDT0x );
+            if (fabs(aAngleT1T0) > aTolAng) {
+              aDT1T0=aDT1x^aDT0x;
+              anAxT1T0.SetLocation( aV1x );
+              anAxT1T0.SetDirection( aDT1T0 );
+              aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
+
+              aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
+            }
 
-          // rotation 2
-          if ( theHasAngles ) {
-            anAx1.SetLocation( aV1x );
-            anAx1.SetDirection( aDT1x );
-            aTrsfRot.SetRotation( anAx1, aAngle1x );
+            // rotation 2
+            if ( theHasAngles ) {
+              anAx1.SetLocation( aV1x );
+              anAx1.SetDirection( aDT1x );
+              aTrsfRot.SetRotation( anAx1, aAngle1x );
 
-            aPN1 = aPN1.Transformed( aTrsfRot );
-          }
+              aPN1 = aPN1.Transformed( aTrsfRot );
+            }
 
-          // make new node
-          //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
-          if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
-            // create additional node
-            double x = ( aPN1.X() + aPN0.X() )/2.;
-            double y = ( aPN1.Y() + aPN0.Y() )/2.;
-            double z = ( aPN1.Z() + aPN0.Z() )/2.;
-            const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
+            // make new node
+            //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
+            if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+              // create additional node
+              double x = ( aPN1.X() + aPN0.X() )/2.;
+              double y = ( aPN1.Y() + aPN0.Y() )/2.;
+              double z = ( aPN1.Z() + aPN0.Z() )/2.;
+              const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
+              myLastCreatedNodes.Append(newNode);
+              srcNodes.Append( node );
+              listNewNodes.push_back( newNode );
+            }
+            const SMDS_MeshNode* newNode = aMesh->AddNode( aPN1.X(), aPN1.Y(), aPN1.Z() );
             myLastCreatedNodes.Append(newNode);
             srcNodes.Append( node );
             listNewNodes.push_back( newNode );
-          }
-          aX = aPN1.X();
-          aY = aPN1.Y();
-          aZ = aPN1.Z();
-          const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
-          myLastCreatedNodes.Append(newNode);
-          srcNodes.Append( node );
-          listNewNodes.push_back( newNode );
 
-          aPN0 = aPN1;
-          aP0x = aP1x;
-          aV0x = aV1x;
-          aDT0x = aDT1x;
+            aPN0 = aPN1;
+            aP0x = aP1x;
+            aV0x = aV1x;
+            aDT0x = aDT1x;
+          }
         }
-      }
 
-      else {
-        // if current elem is quadratic and current node is not medium
-        // we have to check - may be it is needed to insert additional nodes
-        if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
-          list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
-          if(listNewNodes.size()==aNbTP-1) {
-            vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
-            gp_XYZ P(node->X(), node->Y(), node->Z());
-            list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
-            int i;
-            for(i=0; i<aNbTP-1; i++) {
-              const SMDS_MeshNode* N = *it;
-              double x = ( N->X() + P.X() )/2.;
-              double y = ( N->Y() + P.Y() )/2.;
-              double z = ( N->Z() + P.Z() )/2.;
-              const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
-              srcNodes.Append( node );
-              myLastCreatedNodes.Append(newN);
-              aNodes[2*i] = newN;
-              aNodes[2*i+1] = N;
-              P = gp_XYZ(N->X(),N->Y(),N->Z());
-            }
-            listNewNodes.clear();
-            for(i=0; i<2*(aNbTP-1); i++) {
-              listNewNodes.push_back(aNodes[i]);
+        else {
+          // if current elem is quadratic and current node is not medium
+          // we have to check - may be it is needed to insert additional nodes
+          if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+            list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
+            if(listNewNodes.size()==aNbTP-1) {
+              vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
+              gp_XYZ P(node->X(), node->Y(), node->Z());
+              list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
+              int i;
+              for(i=0; i<aNbTP-1; i++) {
+                const SMDS_MeshNode* N = *it;
+                double x = ( N->X() + P.X() )/2.;
+                double y = ( N->Y() + P.Y() )/2.;
+                double z = ( N->Z() + P.Z() )/2.;
+                const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
+                srcNodes.Append( node );
+                myLastCreatedNodes.Append(newN);
+                aNodes[2*i] = newN;
+                aNodes[2*i+1] = N;
+                P = gp_XYZ(N->X(),N->Y(),N->Z());
+              }
+              listNewNodes.clear();
+              for(i=0; i<2*(aNbTP-1); i++) {
+                listNewNodes.push_back(aNodes[i]);
+              }
             }
           }
         }
-      }
 
-      newNodesItVec.push_back( nIt );
+        newNodesItVec.push_back( nIt );
+      }
+      // make new elements
+      //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
+      //              newNodesItVec[0]->second.size(), myLastCreatedElems );
+      sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
     }
-    // make new elements
-    //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
-    //              newNodesItVec[0]->second.size(), myLastCreatedElems );
-    sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
   }
 
-  makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
+  makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], aNbTP-1, srcElems );
 
   if ( theMakeGroups )
     generateGroups( srcNodes, srcElems, "extruded");
@@ -5601,10 +6608,12 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
     groupPostfix = "transformed";
   }
 
-  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
   SMESHDS_Mesh* aMesh    = GetMeshDS();
 
+  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
+  SMESH_MeshEditor* editor = theTargetMesh ? & targetMeshEditor : theCopy ? this : 0;
+  SMESH_MeshEditor::ElemFeatures elemType;
 
   // map old node to new one
   TNodeNodeMap nodeMap;
@@ -5636,70 +6645,68 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
 
   // loop on elements to transform nodes : first orphan nodes then elems
   TIDSortedElemSet::iterator itElem;
-  TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
+  TIDSortedElemSet *elements[] = { &orphanNode, &theElems };
   for (int i=0; i<2; i++)
-  for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
-    const SMDS_MeshElement* elem = *itElem;
-    if ( !elem )
-      continue;
-
-    // loop on elem nodes
-    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-    while ( itN->more() ) {
-
-      const SMDS_MeshNode* node = cast2Node( itN->next() );
-      // check if a node has been already transformed
-      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
-        nodeMap.insert( make_pair ( node, node ));
-      if ( !n2n_isnew.second )
+    for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ )
+    {
+      const SMDS_MeshElement* elem = *itElem;
+      if ( !elem )
         continue;
 
+      // loop on elem nodes
       double coord[3];
-      coord[0] = node->X();
-      coord[1] = node->Y();
-      coord[2] = node->Z();
-      theTrsf.Transforms( coord[0], coord[1], coord[2] );
-      if ( theTargetMesh ) {
-        const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
-        n2n_isnew.first->second = newNode;
-        myLastCreatedNodes.Append(newNode);
-        srcNodes.Append( node );
-      }
-      else if ( theCopy ) {
-        const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
-        n2n_isnew.first->second = newNode;
-        myLastCreatedNodes.Append(newNode);
-        srcNodes.Append( node );
-      }
-      else {
-        aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
-        // node position on shape becomes invalid
-        const_cast< SMDS_MeshNode* > ( node )->SetPosition
-          ( SMDS_SpacePosition::originSpacePosition() );
-      }
+      SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+      while ( itN->more() )
+      {
+        const SMDS_MeshNode* node = cast2Node( itN->next() );
+        // check if a node has been already transformed
+        pair<TNodeNodeMap::iterator,bool> n2n_isnew =
+          nodeMap.insert( make_pair ( node, node ));
+        if ( !n2n_isnew.second )
+          continue;
 
-      // keep inverse elements
-      if ( !theCopy && !theTargetMesh && needReverse ) {
-        SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
-        while ( invElemIt->more() ) {
-          const SMDS_MeshElement* iel = invElemIt->next();
-          inverseElemSet.insert( iel );
+        node->GetXYZ( coord );
+        theTrsf.Transforms( coord[0], coord[1], coord[2] );
+        if ( theTargetMesh ) {
+          const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
+          n2n_isnew.first->second = newNode;
+          myLastCreatedNodes.Append(newNode);
+          srcNodes.Append( node );
+        }
+        else if ( theCopy ) {
+          const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+          n2n_isnew.first->second = newNode;
+          myLastCreatedNodes.Append(newNode);
+          srcNodes.Append( node );
+        }
+        else {
+          aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
+          // node position on shape becomes invalid
+          const_cast< SMDS_MeshNode* > ( node )->SetPosition
+            ( SMDS_SpacePosition::originSpacePosition() );
+        }
+
+        // keep inverse elements
+        if ( !theCopy && !theTargetMesh && needReverse ) {
+          SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
+          while ( invElemIt->more() ) {
+            const SMDS_MeshElement* iel = invElemIt->next();
+            inverseElemSet.insert( iel );
+          }
         }
       }
-    }
-  }
+    } // loop on elems in { &orphanNode, &theElems };
 
   // either create new elements or reverse mirrored ones
   if ( !theCopy && !needReverse && !theTargetMesh )
     return PGroupIDs();
 
-  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
-  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
-    theElems.insert( *invElemIt );
+  theElems.insert( inverseElemSet.begin(),inverseElemSet.end() );
 
   // Replicate or reverse elements
 
   std::vector<int> iForw;
+  vector<const SMDS_MeshNode*> nodes;
   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
   {
     const SMDS_MeshElement* elem = *itElem;
@@ -5707,125 +6714,47 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
 
     SMDSAbs_GeometryType geomType = elem->GetGeomType();
     int                  nbNodes  = elem->NbNodes();
-    if ( geomType == SMDSGeom_POINT ) continue; // node
+    if ( geomType == SMDSGeom_NONE ) continue; // node
 
-    switch ( geomType ) {
+    nodes.resize( nbNodes );
 
-    case SMDSGeom_POLYGON:  // ---------------------- polygon
+    if ( geomType == SMDSGeom_POLYHEDRA )  // ------------------ polyhedral volume
+    {
+      const SMDS_VtkVolume* aPolyedre = dynamic_cast<const SMDS_VtkVolume*>( elem );
+      if (!aPolyedre)
+        continue;
+      nodes.clear();
+      bool allTransformed = true;
+      int nbFaces = aPolyedre->NbFaces();
+      for (int iface = 1; iface <= nbFaces && allTransformed; iface++)
       {
-        vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
-        int iNode = 0;
-        SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-        while (itN->more()) {
-          const SMDS_MeshNode* node =
-            static_cast<const SMDS_MeshNode*>(itN->next());
+        int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
+        for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++)
+        {
+          const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
           TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
-          if (nodeMapIt == nodeMap.end())
-            break; // not all nodes transformed
-          if (needReverse) {
-            // reverse mirrored faces and volumes
-            poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
-          } else {
-            poly_nodes[iNode] = (*nodeMapIt).second;
-          }
-          iNode++;
-        }
-        if ( iNode != nbNodes )
-          continue; // not all nodes transformed
-
-        if ( theTargetMesh ) {
-          myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
-          srcElems.Append( elem );
-        }
-        else if ( theCopy ) {
-          myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
-          srcElems.Append( elem );
-        }
-        else {
-          aMesh->ChangePolygonNodes(elem, poly_nodes);
-        }
-      }
-      break;
-
-    case SMDSGeom_POLYHEDRA:  // ------------------ polyhedral volume
-      {
-        const SMDS_VtkVolume* aPolyedre =
-          dynamic_cast<const SMDS_VtkVolume*>( elem );
-        if (!aPolyedre) {
-          MESSAGE("Warning: bad volumic element");
-          continue;
-        }
-
-        vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
-        vector<int> quantities; quantities.reserve( nbNodes );
-
-        bool allTransformed = true;
-        int nbFaces = aPolyedre->NbFaces();
-        for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
-          int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
-          for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
-            const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
-            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
-            if (nodeMapIt == nodeMap.end()) {
-              allTransformed = false; // not all nodes transformed
-            } else {
-              poly_nodes.push_back((*nodeMapIt).second);
-            }
-            if ( needReverse && allTransformed )
-              std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
-          }
-          quantities.push_back(nbFaceNodes);
-        }
-        if ( !allTransformed )
-          continue; // not all nodes transformed
-
-        if ( theTargetMesh ) {
-          myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
-          srcElems.Append( elem );
-        }
-        else if ( theCopy ) {
-          myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
-          srcElems.Append( elem );
-        }
-        else {
-          aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
-        }
-      }
-      break;
-
-    case SMDSGeom_BALL: // -------------------- Ball
-      {
-        if ( !theCopy && !theTargetMesh ) continue;
-
-        TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) );
-        if (nodeMapIt == nodeMap.end())
-          continue; // not all nodes transformed
-
-        double diameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
-        if ( theTargetMesh ) {
-          myLastCreatedElems.Append(aTgtMesh->AddBall( nodeMapIt->second, diameter ));
-          srcElems.Append( elem );
-        }
-        else {
-          myLastCreatedElems.Append(aMesh->AddBall( nodeMapIt->second, diameter ));
-          srcElems.Append( elem );
+          if ( nodeMapIt == nodeMap.end() )
+            allTransformed = false; // not all nodes transformed
+          else
+            nodes.push_back((*nodeMapIt).second);
         }
+        if ( needReverse && allTransformed )
+          std::reverse( nodes.end() - nbFaceNodes, nodes.end() );
       }
-      break;
-
-    default: // ----------------------- Regular elements
-
+      if ( !allTransformed )
+        continue; // not all nodes transformed
+    }
+    else // ----------------------- the rest element types
+    {
       while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
-      const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
-      const std::vector<int>& i = needReverse ? iRev : iForw;
+      const vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType(), nbNodes );
+      const vector<int>&    i = needReverse ? iRev : iForw;
 
       // find transformed nodes
-      vector<const SMDS_MeshNode*> nodes(nbNodes);
       int iNode = 0;
       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
       while ( itN->more() ) {
-        const SMDS_MeshNode* node =
-          static_cast<const SMDS_MeshNode*>( itN->next() );
+        const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
         if ( nodeMapIt == nodeMap.end() )
           break; // not all nodes transformed
@@ -5833,32 +6762,29 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
       }
       if ( iNode != nbNodes )
         continue; // not all nodes transformed
+    }
 
-      if ( theTargetMesh ) {
-        if ( SMDS_MeshElement* copy =
-             targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
-          myLastCreatedElems.Append( copy );
-          srcElems.Append( elem );
-        }
-      }
-      else if ( theCopy ) {
-        if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
-          srcElems.Append( elem );
-      }
-      else {
-        // reverse element as it was reversed by transformation
-        if ( nbNodes > 2 )
-          aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
-      }
-    } // switch ( geomType )
+    if ( editor ) {
+      // copy in this or a new mesh
+      if ( editor->AddElement( nodes, elemType.Init( elem, /*basicOnly=*/false )))
+        srcElems.Append( elem );
+    }
+    else {
+      // reverse element as it was reversed by transformation
+      if ( nbNodes > 2 )
+        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
+    }
 
   } // loop on elements
 
+  if ( editor && editor != this )
+    myLastCreatedElems = editor->myLastCreatedElems;
+
   PGroupIDs newGroupIDs;
 
   if ( ( theMakeGroups && theCopy ) ||
        ( theMakeGroups && theTargetMesh ) )
-    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
+    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh, false );
 
   return newGroupIDs;
 }
@@ -5866,9 +6792,11 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
 //=======================================================================
 /*!
  * \brief Create groups of elements made during transformation
- * \param nodeGens - nodes making corresponding myLastCreatedNodes
- * \param elemGens - elements making corresponding myLastCreatedElems
- * \param postfix - to append to names of new groups
+ *  \param nodeGens - nodes making corresponding myLastCreatedNodes
+ *  \param elemGens - elements making corresponding myLastCreatedElems
+ *  \param postfix - to append to names of new groups
+ *  \param targetMesh - mesh to create groups in
+ *  \param topPresent - is there "top" elements that are created by sweeping
  */
 //=======================================================================
 
@@ -5876,40 +6804,53 @@ SMESH_MeshEditor::PGroupIDs
 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
                                  const SMESH_SequenceOfElemPtr& elemGens,
                                  const std::string&             postfix,
-                                 SMESH_Mesh*                    targetMesh)
+                                 SMESH_Mesh*                    targetMesh,
+                                 const bool                     topPresent)
 {
   PGroupIDs newGroupIDs( new list<int> );
   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
 
   // Sort existing groups by types and collect their names
 
-  // to store an old group and a generated new one
-  typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
+  // containers to store an old group and generated new ones;
+  // 1st new group is for result elems of different type than a source one;
+  // 2nd new group is for same type result elems ("top" group at extrusion)
+  using boost::tuple;
+  using boost::make_tuple;
+  typedef tuple< SMESHDS_GroupBase*, SMESHDS_Group*, SMESHDS_Group* > TOldNewGroup;
   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
+  vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups
   // group names
   set< string > groupNames;
-  //
-  SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
+
   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
-  while ( groupIt->more() ) {
+  if ( !groupIt->more() ) return newGroupIDs;
+
+  int newGroupID = mesh->GetGroupIds().back()+1;
+  while ( groupIt->more() )
+  {
     SMESH_Group * group = groupIt->next();
     if ( !group ) continue;
     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
     if ( !groupDS || groupDS->IsEmpty() ) continue;
-    groupNames.insert( group->GetName() );
+    groupNames.insert    ( group->GetName() );
     groupDS->SetStoreName( group->GetName() );
-    groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
+    const SMDSAbs_ElementType type = groupDS->GetType();
+    SMESHDS_Group* newGroup    = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
+    SMESHDS_Group* newTopGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
+    groupsByType[ type ].push_back( make_tuple( groupDS, newGroup, newTopGroup ));
+    orderedOldNewGroups.push_back( & groupsByType[ type ].back() );
   }
 
-  // Groups creation
+  // Loop on nodes and elements to add them in new groups
 
-  // loop on nodes and elements
+  vector< const SMDS_MeshElement* > resultElems;
   for ( int isNodes = 0; isNodes < 2; ++isNodes )
   {
     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
     if ( gens.Length() != elems.Length() )
-      throw SALOME_Exception(LOCALIZED("invalid args"));
+      throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args");
 
     // loop on created elements
     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
@@ -5920,13 +6861,13 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
         continue;
       }
       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
-      if ( groupsOldNew.empty() ) {
+      if ( groupsOldNew.empty() ) { // no groups of this type at all
         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
           ++iElem; // skip all elements made by sourceElem
         continue;
       }
-      // collect all elements made by sourceElem
-      list< const SMDS_MeshElement* > resultElems;
+      // collect all elements made by the iElem-th sourceElem
+      resultElems.clear();
       if ( const SMDS_MeshElement* resElem = elems( iElem ))
         if ( resElem != sourceElem )
           resultElems.push_back( resElem );
@@ -5934,1463 +6875,185 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
           if ( resElem != sourceElem )
             resultElems.push_back( resElem );
-      // do not generate element groups from node ones
-//      if ( sourceElem->GetType() == SMDSAbs_Node &&
-//           elems( iElem )->GetType() != SMDSAbs_Node )
-//        continue;
 
-      // add resultElems to groups made by ones the sourceElem belongs to
+      const SMDS_MeshElement* topElem = 0;
+      if ( isNodes ) // there must be a top element
+      {
+        topElem = resultElems.back();
+        resultElems.pop_back();
+      }
+      else
+      {
+        vector< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin();
+        for ( ; resElemIt != resultElems.rend() ; ++resElemIt )
+          if ( (*resElemIt)->GetType() == sourceElem->GetType() )
+          {
+            topElem = *resElemIt;
+            *resElemIt = 0; // erase *resElemIt
+            break;
+          }
+      }
+      // add resultElems to groups originted from ones the sourceElem belongs to
       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
       {
-        SMESHDS_GroupBase* oldGroup = gOldNew->first;
-        if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
+        SMESHDS_GroupBase* oldGroup = gOldNew->get<0>();
+        if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup
         {
-          SMDS_MeshGroup* & newGroup = gOldNew->second;
-          if ( !newGroup )// create a new group
-          {
-            // make a name
-            string name = oldGroup->GetStoreName();
-            if ( !targetMesh ) {
-              name += "_";
-              name += postfix;
-              int nb = 0;
-              while ( !groupNames.insert( name ).second ) // name exists
-              {
-                if ( nb == 0 ) {
-                  name += "_1";
-                }
-                else {
-                  TCollection_AsciiString nbStr(nb+1);
-                  name.resize( name.rfind('_')+1 );
-                  name += nbStr.ToCString();
-                }
-                ++nb;
-              }
-            }
-            // make a group
-            int id;
-            SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
-                                                 name.c_str(), id );
-            SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
-            newGroup = & groupDS->SMDSGroup();
-            newGroupIDs->push_back( id );
-          }
-
           // fill in a new group
-          list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
+          SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup();
+          vector< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
-            newGroup->Add( *resElemIt );
+            if ( *resElemIt )
+              newGroup.Add( *resElemIt );
+
+          // fill a "top" group
+          if ( topElem )
+          {
+            SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup();
+            newTopGroup.Add( topElem );
+         }
         }
       }
     } // loop on created elements
   }// loop on nodes and elements
 
+  // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups
+
+  list<int> topGrouIds;
+  for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i )
+  {
+    SMESHDS_GroupBase* oldGroupDS =   orderedOldNewGroups[i]->get<0>();
+    SMESHDS_Group*   newGroups[2] = { orderedOldNewGroups[i]->get<1>(),
+                                      orderedOldNewGroups[i]->get<2>() };
+    for ( int is2nd = 0; is2nd < 2; ++is2nd )
+    {
+      SMESHDS_Group* newGroupDS = newGroups[ is2nd ];
+      if ( newGroupDS->IsEmpty() )
+      {
+        mesh->GetMeshDS()->RemoveGroup( newGroupDS );
+      }
+      else
+      {
+        // set group type
+        newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
+
+        // make a name
+        const bool isTop = ( topPresent &&
+                             newGroupDS->GetType() == oldGroupDS->GetType() &&
+                             is2nd );
+
+        string name = oldGroupDS->GetStoreName();
+        { // remove trailing whitespaces (issue 22599)
+          size_t size = name.size();
+          while ( size > 1 && isspace( name[ size-1 ]))
+            --size;
+          if ( size != name.size() )
+          {
+            name.resize( size );
+            oldGroupDS->SetStoreName( name.c_str() );
+          }
+        }
+        if ( !targetMesh ) {
+          string suffix = ( isTop ? "top": postfix.c_str() );
+          name += "_";
+          name += suffix;
+          int nb = 1;
+          while ( !groupNames.insert( name ).second ) // name exists
+            name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << suffix << "_" << nb++;
+        }
+        else if ( isTop ) {
+          name += "_top";
+        }
+        newGroupDS->SetStoreName( name.c_str() );
+
+        // make a SMESH_Groups
+        mesh->AddGroup( newGroupDS );
+        if ( isTop )
+          topGrouIds.push_back( newGroupDS->GetID() );
+        else
+          newGroupIDs->push_back( newGroupDS->GetID() );
+      }
+    }
+  }
+  newGroupIDs->splice( newGroupIDs->end(), topGrouIds );
+
   return newGroupIDs;
 }
 
 //================================================================================
 /*!
- * \brief Return list of group of nodes close to each other within theTolerance
- *        Search among theNodes or in the whole mesh if theNodes is empty using
- *        an Octree algorithm
+ *  * \brief Return list of group of nodes close to each other within theTolerance
+ *  *        Search among theNodes or in the whole mesh if theNodes is empty using
+ *  *        an Octree algorithm
+ *  \param [in,out] theNodes - the nodes to treat
+ *  \param [in]     theTolerance - the tolerance
+ *  \param [out]    theGroupsOfNodes - the result groups of coincident nodes
+ *  \param [in]     theSeparateCornersAndMedium - if \c true, in quadratic mesh puts 
+ *         corner and medium nodes in separate groups
  */
 //================================================================================
 
 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
                                             const double         theTolerance,
-                                            TListOfListOfNodes & theGroupsOfNodes)
+                                            TListOfListOfNodes & theGroupsOfNodes,
+                                            bool                 theSeparateCornersAndMedium)
 {
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
-  if ( theNodes.empty() )
-  { // get all nodes in the mesh
-    SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
-    while ( nIt->more() )
-      theNodes.insert( theNodes.end(),nIt->next());
-  }
-
-  SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
-}
+  if ( myMesh->NbEdges  ( ORDER_QUADRATIC ) +
+       myMesh->NbFaces  ( ORDER_QUADRATIC ) +
+       myMesh->NbVolumes( ORDER_QUADRATIC ) == 0 )
+    theSeparateCornersAndMedium = false;
 
+  TIDSortedNodeSet& corners = theNodes;
+  TIDSortedNodeSet  medium;
 
-//=======================================================================
-/*!
- * \brief Implementation of search for the node closest to point
- */
-//=======================================================================
-
-struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
-{
-  //---------------------------------------------------------------------
-  /*!
-   * \brief Constructor
-   */
-  SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
-  {
-    myMesh = ( SMESHDS_Mesh* ) theMesh;
-
-    TIDSortedNodeSet nodes;
-    if ( theMesh ) {
-      SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
-      while ( nIt->more() )
-        nodes.insert( nodes.end(), nIt->next() );
-    }
-    myOctreeNode = new SMESH_OctreeNode(nodes) ;
-
-    // get max size of a leaf box
-    SMESH_OctreeNode* tree = myOctreeNode;
-    while ( !tree->isLeaf() )
-    {
-      SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
-      if ( cIt->more() )
-        tree = cIt->next();
-    }
-    myHalfLeafSize = tree->maxSize() / 2.;
-  }
-
-  //---------------------------------------------------------------------
-  /*!
-   * \brief Move node and update myOctreeNode accordingly
-   */
-  void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
-  {
-    myOctreeNode->UpdateByMoveNode( node, toPnt );
-    myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
-  }
-
-  //---------------------------------------------------------------------
-  /*!
-   * \brief Do it's job
-   */
-  const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
-  {
-    map<double, const SMDS_MeshNode*> dist2Nodes;
-    myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
-    if ( !dist2Nodes.empty() )
-      return dist2Nodes.begin()->second;
-    list<const SMDS_MeshNode*> nodes;
-    //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
-
-    double minSqDist = DBL_MAX;
-    if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
-    {
-      // sort leafs by their distance from thePnt
-      typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
-      TDistTreeMap treeMap;
-      list< SMESH_OctreeNode* > treeList;
-      list< SMESH_OctreeNode* >::iterator trIt;
-      treeList.push_back( myOctreeNode );
-
-      gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
-      bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
-      for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
-      {
-        SMESH_OctreeNode* tree = *trIt;
-        if ( !tree->isLeaf() ) // put children to the queue
-        {
-          if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
-          SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
-          while ( cIt->more() )
-            treeList.push_back( cIt->next() );
-        }
-        else if ( tree->NbNodes() ) // put a tree to the treeMap
-        {
-          const Bnd_B3d& box = tree->getBox();
-          double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
-          pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
-          if ( !it_in.second ) // not unique distance to box center
-            treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
-        }
-      }
-      // find distance after which there is no sense to check tree's
-      double sqLimit = DBL_MAX;
-      TDistTreeMap::iterator sqDist_tree = treeMap.begin();
-      if ( treeMap.size() > 5 ) {
-        SMESH_OctreeNode* closestTree = sqDist_tree->second;
-        const Bnd_B3d& box = closestTree->getBox();
-        double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
-        sqLimit = limit * limit;
-      }
-      // get all nodes from trees
-      for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
-        if ( sqDist_tree->first > sqLimit )
-          break;
-        SMESH_OctreeNode* tree = sqDist_tree->second;
-        tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
-      }
-    }
-    // find closest among nodes
-    minSqDist = DBL_MAX;
-    const SMDS_MeshNode* closestNode = 0;
-    list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
-    for ( ; nIt != nodes.end(); ++nIt ) {
-      double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
-      if ( minSqDist > sqDist ) {
-        closestNode = *nIt;
-        minSqDist = sqDist;
-      }
-    }
-    return closestNode;
-  }
-
-  //---------------------------------------------------------------------
-  /*!
-   * \brief Destructor
-   */
-  ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
-
-  //---------------------------------------------------------------------
-  /*!
-   * \brief Return the node tree
-   */
-  const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
-
-private:
-  SMESH_OctreeNode* myOctreeNode;
-  SMESHDS_Mesh*     myMesh;
-  double            myHalfLeafSize; // max size of a leaf box
-};
-
-//=======================================================================
-/*!
- * \brief Return SMESH_NodeSearcher
- */
-//=======================================================================
-
-SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
-{
-  return new SMESH_NodeSearcherImpl( GetMeshDS() );
-}
-
-// ========================================================================
-namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
-{
-  const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
-  const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
-  const double NodeRadius = 1e-9;  // to enlarge bnd box of element
-
-  //=======================================================================
-  /*!
-   * \brief Octal tree of bounding boxes of elements
-   */
-  //=======================================================================
-
-  class ElementBndBoxTree : public SMESH_Octree
-  {
-  public:
-
-    ElementBndBoxTree(const SMDS_Mesh&     mesh,
-                      SMDSAbs_ElementType  elemType,
-                      SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(),
-                      double               tolerance = NodeRadius );
-    void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems );
-    void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
-    void getElementsInSphere ( const gp_XYZ& center,
-                               const double  radius, TIDSortedElemSet& foundElems);
-    size_t getSize() { return std::max( _size, _elements.size() ); }
-    ~ElementBndBoxTree();
-
-  protected:
-    ElementBndBoxTree():_size(0) {}
-    SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
-    void          buildChildrenData();
-    Bnd_B3d*      buildRootBox();
-  private:
-    //!< Bounding box of element
-    struct ElementBox : public Bnd_B3d
-    {
-      const SMDS_MeshElement* _element;
-      int                     _refCount; // an ElementBox can be included in several tree branches
-      ElementBox(const SMDS_MeshElement* elem, double tolerance);
-    };
-    vector< ElementBox* > _elements;
-    size_t                _size;
-  };
-
-  //================================================================================
-  /*!
-   * \brief ElementBndBoxTree creation
-   */
-  //================================================================================
-
-  ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
-    :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
-  {
-    int nbElems = mesh.GetMeshInfo().NbElements( elemType );
-    _elements.reserve( nbElems );
-
-    SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
-    while ( elemIt->more() )
-      _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
-
-    compute();
-  }
-
-  //================================================================================
-  /*!
-   * \brief Destructor
-   */
-  //================================================================================
-
-  ElementBndBoxTree::~ElementBndBoxTree()
-  {
-    for ( int i = 0; i < _elements.size(); ++i )
-      if ( --_elements[i]->_refCount <= 0 )
-        delete _elements[i];
-  }
-
-  //================================================================================
-  /*!
-   * \brief Return the maximal box
-   */
-  //================================================================================
-
-  Bnd_B3d* ElementBndBoxTree::buildRootBox()
-  {
-    Bnd_B3d* box = new Bnd_B3d;
-    for ( int i = 0; i < _elements.size(); ++i )
-      box->Add( *_elements[i] );
-    return box;
-  }
-
-  //================================================================================
-  /*!
-   * \brief Redistrubute element boxes among children
-   */
-  //================================================================================
-
-  void ElementBndBoxTree::buildChildrenData()
-  {
-    for ( int i = 0; i < _elements.size(); ++i )
-    {
-      for (int j = 0; j < 8; j++)
-      {
-        if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
-        {
-          _elements[i]->_refCount++;
-          ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
-        }
-      }
-      _elements[i]->_refCount--;
-    }
-    _size = _elements.size();
-    SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory
-
-    for (int j = 0; j < 8; j++)
-    {
-      ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
-      if ( child->_elements.size() <= MaxNbElemsInLeaf )
-        child->myIsLeaf = true;
-
-      if ( child->_elements.capacity() - child->_elements.size() > 1000 )
-        SMESHUtils::CompactVector( child->_elements );
-    }
-  }
-
-  //================================================================================
-  /*!
-   * \brief Return elements which can include the point
-   */
-  //================================================================================
-
-  void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
-                                                TIDSortedElemSet& foundElems)
-  {
-    if ( getBox().IsOut( point.XYZ() ))
-      return;
-
-    if ( isLeaf() )
-    {
-      for ( int i = 0; i < _elements.size(); ++i )
-        if ( !_elements[i]->IsOut( point.XYZ() ))
-          foundElems.insert( _elements[i]->_element );
-    }
-    else
-    {
-      for (int i = 0; i < 8; i++)
-        ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
-    }
-  }
-
-  //================================================================================
-  /*!
-   * \brief Return elements which can be intersected by the line
-   */
-  //================================================================================
-
-  void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
-                                               TIDSortedElemSet& foundElems)
-  {
-    if ( getBox().IsOut( line ))
-      return;
-
-    if ( isLeaf() )
-    {
-      for ( int i = 0; i < _elements.size(); ++i )
-        if ( !_elements[i]->IsOut( line ))
-          foundElems.insert( _elements[i]->_element );
-    }
-    else
-    {
-      for (int i = 0; i < 8; i++)
-        ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
-    }
-  }
-
-  //================================================================================
-  /*!
-   * \brief Return elements from leaves intersecting the sphere
-   */
-  //================================================================================
-
-  void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ&     center,
-                                                const double      radius,
-                                                TIDSortedElemSet& foundElems)
-  {
-    if ( getBox().IsOut( center, radius ))
-      return;
-
-    if ( isLeaf() )
-    {
-      for ( int i = 0; i < _elements.size(); ++i )
-        if ( !_elements[i]->IsOut( center, radius ))
-          foundElems.insert( _elements[i]->_element );
-    }
-    else
-    {
-      for (int i = 0; i < 8; i++)
-        ((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems );
-    }
-  }
-
-  //================================================================================
-  /*!
-   * \brief Construct the element box
-   */
-  //================================================================================
-
-  ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
-  {
-    _element  = elem;
-    _refCount = 1;
-    SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
-    while ( nIt->more() )
-      Add( SMESH_TNodeXYZ( nIt->next() ));
-    Enlarge( tolerance );
-  }
-
-} // namespace
-
-//=======================================================================
-/*!
- * \brief Implementation of search for the elements by point and
- *        of classification of point in 2D mesh
- */
-//=======================================================================
-
-struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
-{
-  SMESHDS_Mesh*                _mesh;
-  SMDS_ElemIteratorPtr         _meshPartIt;
-  ElementBndBoxTree*           _ebbTree;
-  SMESH_NodeSearcherImpl*      _nodeSearcher;
-  SMDSAbs_ElementType          _elementType;
-  double                       _tolerance;
-  bool                         _outerFacesFound;
-  set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
-
-  SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
-    : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
-  ~SMESH_ElementSearcherImpl()
-  {
-    if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
-    if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
-  }
-  virtual int FindElementsByPoint(const gp_Pnt&                      point,
-                                  SMDSAbs_ElementType                type,
-                                  vector< const SMDS_MeshElement* >& foundElements);
-  virtual TopAbs_State GetPointState(const gp_Pnt& point);
-  virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt&       point,
-                                                 SMDSAbs_ElementType type );
-
-  void GetElementsNearLine( const gp_Ax1&                      line,
-                            SMDSAbs_ElementType                type,
-                            vector< const SMDS_MeshElement* >& foundElems);
-  double getTolerance();
-  bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
-                            const double tolerance, double & param);
-  void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
-  bool isOuterBoundary(const SMDS_MeshElement* face) const
-  {
-    return _outerFaces.empty() || _outerFaces.count(face);
-  }
-  struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
-  {
-    const SMDS_MeshElement* _face;
-    gp_Vec                  _faceNorm;
-    bool                    _coincides; //!< the line lays in face plane
-    TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
-      : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
-  };
-  struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
-  {
-    SMESH_TLink      _link;
-    TIDSortedElemSet _faces;
-    TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
-      : _link( n1, n2 ), _faces( &face, &face + 1) {}
-  };
-};
-
-ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
-{
-  return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
-             << ", _coincides="<<i._coincides << ")";
-}
-
-//=======================================================================
-/*!
- * \brief define tolerance for search
- */
-//=======================================================================
-
-double SMESH_ElementSearcherImpl::getTolerance()
-{
-  if ( _tolerance < 0 )
-  {
-    const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
-
-    _tolerance = 0;
-    if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
-    {
-      double boxSize = _nodeSearcher->getTree()->maxSize();
-      _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
-    }
-    else if ( _ebbTree && meshInfo.NbElements() > 0 )
-    {
-      double boxSize = _ebbTree->maxSize();
-      _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
-    }
-    if ( _tolerance == 0 )
-    {
-      // define tolerance by size of a most complex element
-      int complexType = SMDSAbs_Volume;
-      while ( complexType > SMDSAbs_All &&
-              meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
-        --complexType;
-      if ( complexType == SMDSAbs_All ) return 0; // empty mesh
-      double elemSize;
-      if ( complexType == int( SMDSAbs_Node ))
-      {
-        SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
-        elemSize = 1;
-        if ( meshInfo.NbNodes() > 2 )
-          elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
-      }
-      else
-      {
-        SMDS_ElemIteratorPtr elemIt =
-            _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
-        const SMDS_MeshElement* elem = elemIt->next();
-        SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
-        SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
-        elemSize = 0;
-        while ( nodeIt->more() )
-        {
-          double dist = n1.Distance( cast2Node( nodeIt->next() ));
-          elemSize = max( dist, elemSize );
-        }
-      }
-      _tolerance = 1e-4 * elemSize;
-    }
-  }
-  return _tolerance;
-}
-
-//================================================================================
-/*!
- * \brief Find intersection of the line and an edge of face and return parameter on line
- */
-//================================================================================
-
-bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
-                                                     const SMDS_MeshElement* face,
-                                                     const double            tol,
-                                                     double &                param)
-{
-  int nbInts = 0;
-  param = 0;
-
-  GeomAPI_ExtremaCurveCurve anExtCC;
-  Handle(Geom_Curve) lineCurve = new Geom_Line( line );
-  
-  int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
-  for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
-  {
-    GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
-                         SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
-    anExtCC.Init( lineCurve, edge);
-    if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
-    {
-      Quantity_Parameter pl, pe;
-      anExtCC.LowerDistanceParameters( pl, pe );
-      param += pl;
-      if ( ++nbInts == 2 )
-        break;
-    }
-  }
-  if ( nbInts > 0 ) param /= nbInts;
-  return nbInts > 0;
-}
-//================================================================================
-/*!
- * \brief Find all faces belonging to the outer boundary of mesh
- */
-//================================================================================
-
-void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
-{
-  if ( _outerFacesFound ) return;
-
-  // Collect all outer faces by passing from one outer face to another via their links
-  // and BTW find out if there are internal faces at all.
-
-  // checked links and links where outer boundary meets internal one
-  set< SMESH_TLink > visitedLinks, seamLinks;
-
-  // links to treat with already visited faces sharing them
-  list < TFaceLink > startLinks;
-
-  // load startLinks with the first outerFace
-  startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
-  _outerFaces.insert( outerFace );
-
-  TIDSortedElemSet emptySet;
-  while ( !startLinks.empty() )
-  {
-    const SMESH_TLink& link  = startLinks.front()._link;
-    TIDSortedElemSet&  faces = startLinks.front()._faces;
-
-    outerFace = *faces.begin();
-    // find other faces sharing the link
-    const SMDS_MeshElement* f;
-    while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
-      faces.insert( f );
-
-    // select another outer face among the found 
-    const SMDS_MeshElement* outerFace2 = 0;
-    if ( faces.size() == 2 )
-    {
-      outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
-    }
-    else if ( faces.size() > 2 )
-    {
-      seamLinks.insert( link );
-
-      // link direction within the outerFace
-      gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
-                   SMESH_TNodeXYZ( link.node2()));
-      int i1 = outerFace->GetNodeIndex( link.node1() );
-      int i2 = outerFace->GetNodeIndex( link.node2() );
-      bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
-      if ( rev ) n1n2.Reverse();
-      // outerFace normal
-      gp_XYZ ofNorm, fNorm;
-      if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
-      {
-        // direction from the link inside outerFace
-        gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
-        // sort all other faces by angle with the dirInOF
-        map< double, const SMDS_MeshElement* > angle2Face;
-        set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
-        for ( ; face != faces.end(); ++face )
-        {
-          if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
-            continue;
-          gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
-          double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
-          if ( angle < 0 ) angle += 2. * M_PI;
-          angle2Face.insert( make_pair( angle, *face ));
-        }
-        if ( !angle2Face.empty() )
-          outerFace2 = angle2Face.begin()->second;
-      }
-    }
-    // store the found outer face and add its links to continue seaching from
-    if ( outerFace2 )
-    {
-      _outerFaces.insert( outerFace );
-      int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
-      for ( int i = 0; i < nbNodes; ++i )
-      {
-        SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
-        if ( visitedLinks.insert( link2 ).second )
-          startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
-      }
-    }
-    startLinks.pop_front();
-  }
-  _outerFacesFound = true;
-
-  if ( !seamLinks.empty() )
-  {
-    // There are internal boundaries touching the outher one,
-    // find all faces of internal boundaries in order to find
-    // faces of boundaries of holes, if any.
-    
-  }
-  else
-  {
-    _outerFaces.clear();
-  }
-}
-
-//=======================================================================
-/*!
- * \brief Find elements of given type where the given point is IN or ON.
- *        Returns nb of found elements and elements them-selves.
- *
- * 'ALL' type means elements of any type excluding nodes, balls and 0D elements 
- */
-//=======================================================================
-
-int SMESH_ElementSearcherImpl::
-FindElementsByPoint(const gp_Pnt&                      point,
-                    SMDSAbs_ElementType                type,
-                    vector< const SMDS_MeshElement* >& foundElements)
-{
-  foundElements.clear();
-
-  double tolerance = getTolerance();
-
-  // =================================================================================
-  if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement || type == SMDSAbs_Ball)
-  {
-    if ( !_nodeSearcher )
-      _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
-
-    const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
-    if ( !closeNode ) return foundElements.size();
-
-    if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
-      return foundElements.size(); // to far from any node
-
-    if ( type == SMDSAbs_Node )
-    {
-      foundElements.push_back( closeNode );
-    }
-    else
-    {
-      SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( type );
-      while ( elemIt->more() )
-        foundElements.push_back( elemIt->next() );
-    }
-  }
-  // =================================================================================
-  else // elements more complex than 0D
-  {
-    if ( !_ebbTree || _elementType != type )
-    {
-      if ( _ebbTree ) delete _ebbTree;
-      _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
-    }
-    TIDSortedElemSet suspectElems;
-    _ebbTree->getElementsNearPoint( point, suspectElems );
-    TIDSortedElemSet::iterator elem = suspectElems.begin();
-    for ( ; elem != suspectElems.end(); ++elem )
-      if ( !SMESH_MeshEditor::IsOut( *elem, point, tolerance ))
-        foundElements.push_back( *elem );
-  }
-  return foundElements.size();
-}
-
-//=======================================================================
-/*!
- * \brief Find an element of given type most close to the given point
- *
- * WARNING: Only face search is implemeneted so far
- */
-//=======================================================================
-
-const SMDS_MeshElement*
-SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt&       point,
-                                          SMDSAbs_ElementType type )
-{
-  const SMDS_MeshElement* closestElem = 0;
-
-  if ( type == SMDSAbs_Face )
-  {
-    if ( !_ebbTree || _elementType != type )
-    {
-      if ( _ebbTree ) delete _ebbTree;
-      _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
-    }
-    TIDSortedElemSet suspectElems;
-    _ebbTree->getElementsNearPoint( point, suspectElems );
-    
-    if ( suspectElems.empty() && _ebbTree->maxSize() > 0 )
-    {
-      gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox().CornerMin() +
-                                 _ebbTree->getBox().CornerMax() );
-      double radius;
-      if ( _ebbTree->getBox().IsOut( point.XYZ() ))
-        radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize();
-      else
-        radius = _ebbTree->maxSize() / pow( 2., _ebbTree->getHeight()) / 2;
-      while ( suspectElems.empty() )
-      {
-        _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
-        radius *= 1.1;
-      }
-    }
-    double minDist = std::numeric_limits<double>::max();
-    multimap< double, const SMDS_MeshElement* > dist2face;
-    TIDSortedElemSet::iterator elem = suspectElems.begin();
-    for ( ; elem != suspectElems.end(); ++elem )
-    {
-      double dist = SMESH_MeshEditor::GetDistance( dynamic_cast<const SMDS_MeshFace*>(*elem),
-                                                   point );
-      if ( dist < minDist + 1e-10)
-      {
-        minDist = dist;
-        dist2face.insert( dist2face.begin(), make_pair( dist, *elem ));
-      }
-    }
-    if ( !dist2face.empty() )
-    {
-      multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin();
-      closestElem = d2f->second;
-      // if there are several elements at the same distance, select one
-      // with GC closest to the point
-      typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
-      double minDistToGC = 0;
-      for ( ++d2f; d2f != dist2face.end() && fabs( d2f->first - minDist ) < 1e-10; ++d2f )
-      {
-        if ( minDistToGC == 0 )
-        {
-          gp_XYZ gc(0,0,0);
-          gc = accumulate( TXyzIterator(closestElem->nodesIterator()),
-                           TXyzIterator(), gc ) / closestElem->NbNodes();
-          minDistToGC = point.SquareDistance( gc );
-        }
-        gp_XYZ gc(0,0,0);
-        gc = accumulate( TXyzIterator( d2f->second->nodesIterator()),
-                         TXyzIterator(), gc ) / d2f->second->NbNodes();
-        double d = point.SquareDistance( gc );
-        if ( d < minDistToGC )
-        {
-          minDistToGC = d;
-          closestElem = d2f->second;
-        }
-      }
-      // cout << "FindClosestTo( " <<point.X()<<", "<<point.Y()<<", "<<point.Z()<<" ) FACE "
-      //      <<closestElem->GetID() << " DIST " << minDist << endl;
-    }
-  }
-  else
-  {
-    // NOT IMPLEMENTED SO FAR
-  }
-  return closestElem;
-}
-
-
-//================================================================================
-/*!
- * \brief Classify the given point in the closed 2D mesh
- */
-//================================================================================
-
-TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
-{
-  double tolerance = getTolerance();
-  if ( !_ebbTree || _elementType != SMDSAbs_Face )
-  {
-    if ( _ebbTree ) delete _ebbTree;
-    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
-  }
-  // Algo: analyse transition of a line starting at the point through mesh boundary;
-  // try three lines parallel to axis of the coordinate system and perform rough
-  // analysis. If solution is not clear perform thorough analysis.
-
-  const int nbAxes = 3;
-  gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
-  map< double, TInters >   paramOnLine2TInters[ nbAxes ];
-  list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
-  multimap< int, int > nbInt2Axis; // to find the simplest case
-  for ( int axis = 0; axis < nbAxes; ++axis )
-  {
-    gp_Ax1 lineAxis( point, axisDir[axis]);
-    gp_Lin line    ( lineAxis );
-
-    TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
-    _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
-
-    // Intersect faces with the line
-
-    map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
-    TIDSortedElemSet::iterator face = suspectFaces.begin();
-    for ( ; face != suspectFaces.end(); ++face )
-    {
-      // get face plane
-      gp_XYZ fNorm;
-      if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
-      gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
-
-      // perform intersection
-      IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
-      if ( !intersection.IsDone() )
-        continue;
-      if ( intersection.IsInQuadric() )
-      {
-        tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
-      }
-      else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
-      {
-        gp_Pnt intersectionPoint = intersection.Point(1);
-        if ( !SMESH_MeshEditor::IsOut( *face, intersectionPoint, tolerance ))
-          u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
-      }
-    }
-    // Analyse intersections roughly
-
-    int nbInter = u2inters.size();
-    if ( nbInter == 0 )
-      return TopAbs_OUT; 
-
-    double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
-    if ( nbInter == 1 ) // not closed mesh
-      return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
-
-    if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
-      return TopAbs_ON;
-
-    if ( (f<0) == (l<0) )
-      return TopAbs_OUT;
-
-    int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
-    int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
-    if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
-      return TopAbs_IN;
-
-    nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
-
-    if ( _outerFacesFound ) break; // pass to thorough analysis
-
-  } // three attempts - loop on CS axes
-
-  // Analyse intersections thoroughly.
-  // We make two loops maximum, on the first one we only exclude touching intersections,
-  // on the second, if situation is still unclear, we gather and use information on
-  // position of faces (internal or outer). If faces position is already gathered,
-  // we make the second loop right away.
-
-  for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
+  if ( theNodes.empty() ) // get all nodes in the mesh
   {
-    multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
-    for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
-    {
-      int axis = nb_axis->second;
-      map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
-
-      gp_Ax1 lineAxis( point, axisDir[axis]);
-      gp_Lin line    ( lineAxis );
-
-      // add tangent intersections to u2inters
-      double param;
-      list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
-      for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
-        if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
-          u2inters.insert(make_pair( param, *tgtInt ));
-      tangentInters[ axis ].clear();
-
-      // Count intersections before and after the point excluding touching ones.
-      // If hasPositionInfo we count intersections of outer boundary only
-
-      int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
-      double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
-      map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
-      bool ok = ! u_int1->second._coincides;
-      while ( ok && u_int1 != u2inters.end() )
-      {
-        double u = u_int1->first;
-        bool touchingInt = false;
-        if ( ++u_int2 != u2inters.end() )
-        {
-          // skip intersections at the same point (if the line passes through edge or node)
-          int nbSamePnt = 0;
-          while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
-          {
-            ++nbSamePnt;
-            ++u_int2;
-          }
-
-          // skip tangent intersections
-          int nbTgt = 0;
-          const SMDS_MeshElement* prevFace = u_int1->second._face;
-          while ( ok && u_int2->second._coincides )
-          {
-            if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
-              ok = false;
-            else
-            {
-              nbTgt++;
-              u_int2++;
-              ok = ( u_int2 != u2inters.end() );
-            }
-          }
-          if ( !ok ) break;
-
-          // skip intersections at the same point after tangent intersections
-          if ( nbTgt > 0 )
-          {
-            double u2 = u_int2->first;
-            ++u_int2;
-            while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
-            {
-              ++nbSamePnt;
-              ++u_int2;
-            }
-          }
-          // decide if we skipped a touching intersection
-          if ( nbSamePnt + nbTgt > 0 )
-          {
-            double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
-            map< double, TInters >::iterator u_int = u_int1;
-            for ( ; u_int != u_int2; ++u_int )
-            {
-              if ( u_int->second._coincides ) continue;
-              double dot = u_int->second._faceNorm * line.Direction();
-              if ( dot > maxDot ) maxDot = dot;
-              if ( dot < minDot ) minDot = dot;
-            }
-            touchingInt = ( minDot*maxDot < 0 );
-          }
-        }
-        if ( !touchingInt )
-        {
-          if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
-          {
-            if ( u < 0 )
-              ++nbIntBeforePoint;
-            else
-              ++nbIntAfterPoint;
-          }
-          if ( u < f ) f = u;
-          if ( u > l ) l = u;
-        }
-
-        u_int1 = u_int2; // to next intersection
-
-      } // loop on intersections with one line
-
-      if ( ok )
+    TIDSortedNodeSet* nodes[2] = { &corners, &medium };
+    SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
+    if ( theSeparateCornersAndMedium )
+      while ( nIt->more() )
       {
-        if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
-          return TopAbs_ON;
-
-        if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
-          return TopAbs_OUT; 
-
-        if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
-          return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
-
-        if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
-          return TopAbs_IN;
-
-        if ( (f<0) == (l<0) )
-          return TopAbs_OUT;
-
-        if ( hasPositionInfo )
-          return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
+        const SMDS_MeshNode* n = nIt->next();
+        TIDSortedNodeSet* & nodeSet = nodes[ SMESH_MesherHelper::IsMedium( n )];
+        nodeSet->insert( nodeSet->end(), n );
       }
-    } // loop on intersections of the tree lines - thorough analysis
-
-    if ( !hasPositionInfo )
-    {
-      // gather info on faces position - is face in the outer boundary or not
-      map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
-      findOuterBoundary( u2inters.begin()->second._face );
-    }
-
-  } // two attempts - with and w/o faces position info in the mesh
-
-  return TopAbs_UNKNOWN;
-}
-
-//=======================================================================
-/*!
- * \brief Return elements possibly intersecting the line
- */
-//=======================================================================
-
-void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
-                                                     SMDSAbs_ElementType                type,
-                                                     vector< const SMDS_MeshElement* >& foundElems)
-{
-  if ( !_ebbTree || _elementType != type )
-  {
-    if ( _ebbTree ) delete _ebbTree;
-    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
-  }
-  TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
-  _ebbTree->getElementsNearLine( line, suspectFaces );
-  foundElems.assign( suspectFaces.begin(), suspectFaces.end());
-}
-
-//=======================================================================
-/*!
- * \brief Return SMESH_ElementSearcher
- */
-//=======================================================================
-
-SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
-{
-  return new SMESH_ElementSearcherImpl( *GetMeshDS() );
-}
-
-//=======================================================================
-/*!
- * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
- */
-//=======================================================================
-
-SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
-{
-  return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
-}
-
-//=======================================================================
-/*!
- * \brief Return true if the point is IN or ON of the element
- */
-//=======================================================================
-
-bool SMESH_MeshEditor::IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
-{
-  if ( element->GetType() == SMDSAbs_Volume)
-  {
-    return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
-  }
-
-  // get ordered nodes
-
-  vector< gp_XYZ > xyz;
-  vector<const SMDS_MeshNode*> nodeList;
-
-  SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
-  if ( element->IsQuadratic() ) {
-    if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
-      nodeIt = f->interlacedNodesElemIterator();
-    else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
-      nodeIt = e->interlacedNodesElemIterator();
+    else
+      while ( nIt->more() )
+        theNodes.insert( theNodes.end(),nIt->next() );
   }
-  while ( nodeIt->more() )
-    {
-      const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
-      xyz.push_back( SMESH_TNodeXYZ(node) );
-      nodeList.push_back(node);
-    }
-
-  int i, nbNodes = element->NbNodes();
-
-  if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
+  else if ( theSeparateCornersAndMedium ) // separate corners from medium nodes
   {
-    // compute face normal
-    gp_Vec faceNorm(0,0,0);
-    xyz.push_back( xyz.front() );
-    nodeList.push_back( nodeList.front() );
-    for ( i = 0; i < nbNodes; ++i )
-    {
-      gp_Vec edge1( xyz[i+1], xyz[i]);
-      gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
-      faceNorm += edge1 ^ edge2;
-    }
-    double normSize = faceNorm.Magnitude();
-    if ( normSize <= tol )
-    {
-      // degenerated face: point is out if it is out of all face edges
-      for ( i = 0; i < nbNodes; ++i )
+    TIDSortedNodeSet::iterator nIt = corners.begin();
+    while ( nIt != corners.end() )
+      if ( SMESH_MesherHelper::IsMedium( *nIt ))
       {
-        SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
-        if ( !IsOut( &edge, point, tol ))
-          return false;
+        medium.insert( medium.end(), *nIt );
+        corners.erase( nIt++ );
       }
-      return true;
-    }
-    faceNorm /= normSize;
-
-    // check if the point lays on face plane
-    gp_Vec n2p( xyz[0], point );
-    if ( fabs( n2p * faceNorm ) > tol )
-      return true; // not on face plane
-
-    // check if point is out of face boundary:
-    // define it by closest transition of a ray point->infinity through face boundary
-    // on the face plane.
-    // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
-    // to find intersections of the ray with the boundary.
-    gp_Vec ray = n2p;
-    gp_Vec plnNorm = ray ^ faceNorm;
-    normSize = plnNorm.Magnitude();
-    if ( normSize <= tol ) return false; // point coincides with the first node
-    plnNorm /= normSize;
-    // for each node of the face, compute its signed distance to the plane
-    vector<double> dist( nbNodes + 1);
-    for ( i = 0; i < nbNodes; ++i )
-    {
-      gp_Vec n2p( xyz[i], point );
-      dist[i] = n2p * plnNorm;
-    }
-    dist.back() = dist.front();
-    // find the closest intersection
-    int    iClosest = -1;
-    double rClosest, distClosest = 1e100;;
-    gp_Pnt pClosest;
-    for ( i = 0; i < nbNodes; ++i )
-    {
-      double r;
-      if ( fabs( dist[i]) < tol )
-        r = 0.;
-      else if ( fabs( dist[i+1]) < tol )
-        r = 1.;
-      else if ( dist[i] * dist[i+1] < 0 )
-        r = dist[i] / ( dist[i] - dist[i+1] );
       else
-        continue; // no intersection
-      gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
-      gp_Vec p2int ( point, pInt);
-      if ( p2int * ray > -tol ) // right half-space
       {
-        double intDist = p2int.SquareMagnitude();
-        if ( intDist < distClosest )
-        {
-          iClosest = i;
-          rClosest = r;
-          pClosest = pInt;
-          distClosest = intDist;
-        }
+        ++nIt;
       }
-    }
-    if ( iClosest < 0 )
-      return true; // no intesections - out
-
-    // analyse transition
-    gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
-    gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
-    gp_Vec p2int ( point, pClosest );
-    bool out = (edgeNorm * p2int) < -tol;
-    if ( rClosest > 0. && rClosest < 1. ) // not node intersection
-      return out;
-
-    // ray pass through a face node; analyze transition through an adjacent edge
-    gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
-    gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
-    gp_Vec edgeAdjacent( p1, p2 );
-    gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
-    bool out2 = (edgeNorm2 * p2int) < -tol;
-
-    bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
-    return covexCorner ? (out || out2) : (out && out2);
-  }
-  if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
-  {
-    // point is out of edge if it is NOT ON any straight part of edge
-    // (we consider quadratic edge as being composed of two straight parts)
-    for ( i = 1; i < nbNodes; ++i )
-    {
-      gp_Vec edge( xyz[i-1], xyz[i]);
-      gp_Vec n1p ( xyz[i-1], point);
-      double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
-      if ( dist > tol )
-        continue;
-      gp_Vec n2p( xyz[i], point );
-      if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
-        continue;
-      return false; // point is ON this part
-    }
-    return true;
-  }
-  // Node or 0D element -------------------------------------------------------------------------
-  {
-    gp_Vec n2p ( xyz[0], point );
-    return n2p.Magnitude() <= tol;
-  }
-  return true;
-}
-
-//=======================================================================
-
-namespace
-{
-  // Position of a point relative to a segment
-  //            .           .
-  //            .  LEFT     .
-  //            .           .
-  //  VERTEX 1  o----ON----->  VERTEX 2
-  //            .           .
-  //            .  RIGHT    .
-  //            .           .
-  enum PositionName { POS_LEFT = 1, POS_VERTEX = 2, POS_RIGHT = 4, //POS_ON = 8,
-                      POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX };
-  struct PointPos
-  {
-    PositionName _name; 
-    int          _index; // index of vertex or segment
-
-    PointPos( PositionName n, int i=-1 ): _name(n), _index(i) {}
-    bool operator < (const PointPos& other ) const
-    {
-      if ( _name == other._name )
-        return  ( _index < 0 || other._index < 0 ) ? false : _index < other._index;
-      return _name < other._name;
-    }
-  };
-
-  //================================================================================
-  /*!
-   * \brief Return of a point relative to a segment
-   *  \param point2D      - the point to analyze position of
-   *  \param xyVec        - end points of segments
-   *  \param index0       - 0-based index of the first point of segment
-   *  \param posToFindOut - flags of positions to detect
-   *  \retval PointPos - point position
-   */
-  //================================================================================
-
-  PointPos getPointPosition( const gp_XY& point2D,
-                             const gp_XY* segEnds,
-                             const int    index0 = 0,
-                             const int    posToFindOut = POS_ALL)
-  {
-    const gp_XY& p1 = segEnds[ index0   ];
-    const gp_XY& p2 = segEnds[ index0+1 ];
-    const gp_XY grad = p2 - p1;
-
-    if ( posToFindOut & POS_VERTEX )
-    {
-      // check if the point2D is at "vertex 1" zone
-      gp_XY pp1[2] = { p1, gp_XY( p1.X() - grad.Y(),
-                                  p1.Y() + grad.X() ) };
-      if ( getPointPosition( point2D, pp1, 0, POS_LEFT|POS_RIGHT )._name == POS_LEFT )
-        return PointPos( POS_VERTEX, index0 );
-
-      // check if the point2D is at "vertex 2" zone
-      gp_XY pp2[2] = { p2, gp_XY( p2.X() - grad.Y(),
-                                  p2.Y() + grad.X() ) };
-      if ( getPointPosition( point2D, pp2, 0, POS_LEFT|POS_RIGHT )._name == POS_RIGHT )
-        return PointPos( POS_VERTEX, index0 + 1);
-    }
-    double edgeEquation =
-      ( point2D.X() - p1.X() ) * grad.Y() - ( point2D.Y() - p1.Y() ) * grad.X();
-    return PointPos( edgeEquation < 0 ? POS_LEFT : POS_RIGHT, index0 );
-  }
-}
-
-//=======================================================================
-/*!
- * \brief Return minimal distance from a point to a face
- *
- * Currently we ignore non-planarity and 2nd order of face
- */
-//=======================================================================
-
-double SMESH_MeshEditor::GetDistance( const SMDS_MeshFace* face,
-                                      const gp_Pnt&        point )
-{
-  double badDistance = -1;
-  if ( !face ) return badDistance;
-
-  // coordinates of nodes (medium nodes, if any, ignored)
-  typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
-  vector<gp_XYZ> xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() );
-  xyz.resize( face->NbCornerNodes()+1 );
-
-  // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis,
-  // and xyz[2] lies in the XZ plane. This is to pass to 2D space on XZ plane.
-  gp_Trsf trsf;
-  gp_Vec OZ ( xyz[0], xyz[1] );
-  gp_Vec OX ( xyz[0], xyz[2] );
-  if ( OZ.Magnitude() < std::numeric_limits<double>::min() )
-  {
-    if ( xyz.size() < 4 ) return badDistance;
-    OZ = gp_Vec ( xyz[0], xyz[2] );
-    OX = gp_Vec ( xyz[0], xyz[3] );
-  }
-  gp_Ax3 tgtCS;
-  try {
-    tgtCS = gp_Ax3( xyz[0], OZ, OX );
-  }
-  catch ( Standard_Failure ) {
-    return badDistance;
-  }
-  trsf.SetTransformation( tgtCS );
-
-  // move all the nodes to 2D
-  vector<gp_XY> xy( xyz.size() );
-  for ( size_t i = 0;i < xyz.size()-1; ++i )
-  {
-    gp_XYZ p3d = xyz[i];
-    trsf.Transforms( p3d );
-    xy[i].SetCoord( p3d.X(), p3d.Z() );
-  }
-  xyz.back() = xyz.front();
-  xy.back() = xy.front();
-
-  // // move the point in 2D
-  gp_XYZ tmpPnt = point.XYZ();
-  trsf.Transforms( tmpPnt );
-  gp_XY point2D( tmpPnt.X(), tmpPnt.Z() );
-
-  // loop on segments of the face to analyze point position ralative to the face
-  set< PointPos > pntPosSet;
-  for ( size_t i = 1; i < xy.size(); ++i )
-  {
-    PointPos pos = getPointPosition( point2D, &xy[0], i-1 );
-    pntPosSet.insert( pos );
   }
 
-  // compute distance
-  PointPos pos = *pntPosSet.begin();
-  // cout << "Face " << face->GetID() << " DIST: ";
-  switch ( pos._name )
-  {
-  case POS_LEFT: {
-    // point is most close to a segment
-    gp_Vec p0p1( point, xyz[ pos._index ] );
-    gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector
-    p1p2.Normalize();
-    double projDist = p0p1 * p1p2; // distance projected to the segment
-    gp_Vec projVec = p1p2 * projDist;
-    gp_Vec distVec = p0p1 - projVec;
-    // cout << distVec.Magnitude()  << ", SEG " << face->GetNode(pos._index)->GetID()
-    //      << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl;
-    return distVec.Magnitude();
-  }
-  case POS_RIGHT: {
-    // point is inside the face
-    double distToFacePlane = tmpPnt.Y();
-    // cout << distToFacePlane << ", INSIDE " << endl;
-    return Abs( distToFacePlane );
-  }
-  case POS_VERTEX: {
-    // point is most close to a node
-    gp_Vec distVec( point, xyz[ pos._index ]);
-    // cout << distVec.Magnitude()  << " VERTEX " << face->GetNode(pos._index)->GetID() << endl;
-    return distVec.Magnitude();
-  }
-  }
-  return badDistance;
+  if ( !corners.empty() )
+    SMESH_OctreeNode::FindCoincidentNodes ( corners, &theGroupsOfNodes, theTolerance );
+  if ( !medium.empty() )
+    SMESH_OctreeNode::FindCoincidentNodes ( medium, &theGroupsOfNodes, theTolerance );
 }
 
 //=======================================================================
 //function : SimplifyFace
-//purpose  :
+//purpose  : split a chain of nodes into several closed chains
 //=======================================================================
-int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
-                                    vector<const SMDS_MeshNode *>&      poly_nodes,
-                                    vector<int>&                        quantities) const
+
+int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *>& faceNodes,
+                                    vector<const SMDS_MeshNode *>&       poly_nodes,
+                                    vector<int>&                         quantities) const
 {
   int nbNodes = faceNodes.size();
 
@@ -7500,6 +7163,12 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
         //MESSAGE("  node to remove " << nToRemove->GetID());
         rmNodeIds.push_back( nToRemove->GetID() );
         AddToSameGroups( nToKeep, nToRemove, aMesh );
+        // set _alwaysComputed to a sub-mesh of VERTEX to enable mesh computing
+        // after MergeNodes() w/o creating node in place of merged ones.
+        const SMDS_PositionPtr& pos = nToRemove->GetPosition();
+        if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX )
+          if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() ))
+            sm->SetIsAlwaysComputed( true );
       }
 
       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
@@ -7511,29 +7180,34 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
   }
   // Change element nodes or remove an element
 
+  set<const SMDS_MeshNode*> nodeSet;
+  vector< const SMDS_MeshNode*> curNodes, uniqueNodes;
+  vector<int> iRepl;
+  ElemFeatures elemType;
+
   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
-  for ( ; eIt != elems.end(); eIt++ ) {
+  for ( ; eIt != elems.end(); eIt++ )
+  {
     const SMDS_MeshElement* elem = *eIt;
-    //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
     int nbNodes = elem->NbNodes();
     int aShapeId = FindShape( elem );
 
-    set<const SMDS_MeshNode*> nodeSet;
-    vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
+    nodeSet.clear();
+    curNodes.resize( nbNodes );
+    uniqueNodes.resize( nbNodes );
+    iRepl.resize( nbNodes );
     int iUnique = 0, iCur = 0, nbRepl = 0;
-    vector<int> iRepl( nbNodes );
 
     // get new seq of nodes
     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-    while ( itN->more() ) {
-      const SMDS_MeshNode* n =
-        static_cast<const SMDS_MeshNode*>( itN->next() );
+    while ( itN->more() )
+    {
+      const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( itN->next() );
 
       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
       if ( nnIt != nodeNodeMap.end() ) { // n sticks
         n = (*nnIt).second;
-        // BUG 0020185: begin
-        {
+        { ////////// BUG 0020185: begin
           bool stopRecur = false;
           set<const SMDS_MeshNode*> nodesRecur;
           nodesRecur.insert(n);
@@ -7549,8 +7223,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
             else
               stopRecur = true;
           }
-        }
-        // BUG 0020185: end
+        } ////////// BUG 0020185: end
       }
       curNodes[ iCur ] = n;
       bool isUnique = nodeSet.insert( n ).second;
@@ -7565,56 +7238,54 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 
     bool isOk = true;
     int nbUniqueNodes = nodeSet.size();
-    //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
-    if ( nbNodes != nbUniqueNodes ) { // some nodes stick
-      // Polygons and Polyhedral volumes
-      if (elem->IsPoly()) {
-
-        if (elem->GetType() == SMDSAbs_Face) {
-          // Polygon
-          vector<const SMDS_MeshNode *> face_nodes (nbNodes);
-          int inode = 0;
-          for (; inode < nbNodes; inode++) {
-            face_nodes[inode] = curNodes[inode];
-          }
+    if ( nbNodes != nbUniqueNodes ) // some nodes stick
+    {
+      if (elem->IsPoly()) // Polygons and Polyhedral volumes
+      {
+        if (elem->GetType() == SMDSAbs_Face) // Polygon
+        {
+          elemType.Init( elem );
+          const bool isQuad = elemType.myIsQuad;
+          if ( isQuad )
+            SMDS_MeshCell::applyInterlace // interlace medium and corner nodes
+              ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, nbNodes ), curNodes );
 
+          // a polygon can divide into several elements
           vector<const SMDS_MeshNode *> polygons_nodes;
           vector<int> quantities;
-          int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
-          if (nbNew > 0) {
-            inode = 0;
-            for (int iface = 0; iface < nbNew; iface++) {
-              int nbNodes = quantities[iface];
-              vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
-              for (int ii = 0; ii < nbNodes; ii++, inode++) {
-                poly_nodes[ii] = polygons_nodes[inode];
+          int nbNew = SimplifyFace( curNodes, polygons_nodes, quantities );
+          if (nbNew > 0)
+          {
+            vector<const SMDS_MeshNode *> face_nodes;
+            int inode = 0;
+            for (int iface = 0; iface < nbNew; iface++)
+            {
+              int nbNewNodes = quantities[iface];
+              face_nodes.assign( polygons_nodes.begin() + inode,
+                                 polygons_nodes.begin() + inode + nbNewNodes );
+              inode += nbNewNodes;
+              if ( isQuad ) // check if a result elem is a valid quadratic polygon
+              {
+                bool isValid = ( nbNewNodes % 2 == 0 );
+                for ( int i = 0; i < nbNewNodes && isValid; ++i )
+                  isValid = ( elem->IsMediumNode( face_nodes[i]) == bool( i % 2 ));
+                elemType.SetQuad( isValid );
+                if ( isValid ) // put medium nodes after corners
+                  SMDS_MeshCell::applyInterlaceRev
+                    ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon,
+                                                          nbNewNodes ), face_nodes );
               }
-              SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
-              myLastCreatedElems.Append(newElem);
-              if (aShapeId)
+              SMDS_MeshElement* newElem = AddElement( face_nodes, elemType );
+              if ( aShapeId )
                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
             }
-
-            MESSAGE("ChangeElementNodes MergeNodes Polygon");
-            //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
-            vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
-            int quid =0;
-            if (nbNew > 0) quid = nbNew - 1;
-            vector<int> newquant(quantities.begin()+quid, quantities.end());
-            const SMDS_MeshElement* newElem = 0;
-            newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
-            myLastCreatedElems.Append(newElem);
-            if ( aShapeId && newElem )
-              aMesh->SetMeshElementOnShape( newElem, aShapeId );
-            rmElemIds.push_back(elem->GetID());
-          }
-          else {
-            rmElemIds.push_back(elem->GetID());
           }
+          rmElemIds.push_back(elem->GetID());
 
-        }
-        else if (elem->GetType() == SMDSAbs_Volume) {
-          // Polyhedral volume
+        } // Polygon
+
+        else if (elem->GetType() == SMDSAbs_Volume) // Polyhedral volume
+        {
           if (nbUniqueNodes < 4) {
             rmElemIds.push_back(elem->GetID());
           }
@@ -7647,18 +7318,17 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
               if (quantities.size() > 3) {
                 // to be done: remove coincident faces
               }
-
-              if (quantities.size() > 3)
-                {
-                  MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
-                  //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
-                  const SMDS_MeshElement* newElem = 0;
-                  newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
-                  myLastCreatedElems.Append(newElem);
-                  if ( aShapeId && newElem )
-                    aMesh->SetMeshElementOnShape( newElem, aShapeId );
-                  rmElemIds.push_back(elem->GetID());
-                }
+
+              if (quantities.size() > 3)
+              {
+                //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
+                const SMDS_MeshElement* newElem =
+                  aMesh->AddPolyhedralVolume(poly_nodes, quantities);
+                myLastCreatedElems.Append(newElem);
+                if ( aShapeId && newElem )
+                  aMesh->SetMeshElementOnShape( newElem, aShapeId );
+                rmElemIds.push_back(elem->GetID());
+              }
             }
             else {
               rmElemIds.push_back(elem->GetID());
@@ -8057,51 +7727,19 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 
     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
 
-    if ( isOk ) { // the elem remains valid after sticking nodes
-      if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
-      {
-        // Change nodes of polyedre
-        const SMDS_VtkVolume* aPolyedre =
-          dynamic_cast<const SMDS_VtkVolume*>( elem );
-        if (aPolyedre) {
-          int nbFaces = aPolyedre->NbFaces();
-
-          vector<const SMDS_MeshNode *> poly_nodes;
-          vector<int> quantities (nbFaces);
-
-          for (int iface = 1; iface <= nbFaces; iface++) {
-            int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
-            quantities[iface - 1] = nbFaceNodes;
-
-            for (inode = 1; inode <= nbFaceNodes; inode++) {
-              const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
-
-              TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
-              if (nnIt != nodeNodeMap.end()) { // curNode sticks
-                curNode = (*nnIt).second;
-              }
-              poly_nodes.push_back(curNode);
-            }
-          }
-          aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
-        }
-      }
-      else // replace non-polyhedron elements
-      {
-        const SMDSAbs_ElementType etyp = elem->GetType();
-        const int elemId               = elem->GetID();
-        const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
-        uniqueNodes.resize(nbUniqueNodes);
+    if ( isOk ) // the non-poly elem remains valid after sticking nodes
+    {
+      elemType.Init( elem ).SetID( elem->GetID() );
 
-        SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
+      SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
+      aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
 
-        aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
-        SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
-        if ( sm && newElem )
-          sm->AddElement( newElem );
-        if ( elem != newElem )
-          ReplaceElemInGroups( elem, newElem, aMesh );
-      }
+      uniqueNodes.resize(nbUniqueNodes);
+      SMDS_MeshElement* newElem = this->AddElement( uniqueNodes, elemType );
+      if ( sm && newElem )
+        sm->AddElement( newElem );
+      if ( elem != newElem )
+        ReplaceElemInGroups( elem, newElem, aMesh );
     }
     else {
       // Remove invalid regular element or invalid polygon
@@ -8115,6 +7753,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
   Remove( rmElemIds, false );
   Remove( rmNodeIds, true );
 
+  return;
 }
 
 
@@ -8150,56 +7789,54 @@ private:
 //purpose  : Return list of group of elements built on the same nodes.
 //           Search among theElements or in the whole mesh if theElements is empty
 //=======================================================================
-void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
-                                         TListOfListOfElementsID &      theGroupsOfElementsID)
+
+void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet &        theElements,
+                                         TListOfListOfElementsID & theGroupsOfElementsID)
 {
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
-  typedef set<const SMDS_MeshElement*> TElemsSet;
   typedef map< SortableElement, int > TMapOfNodeSet;
   typedef list<int> TGroupOfElems;
 
-  TElemsSet elems;
   if ( theElements.empty() )
   { // get all elements in the mesh
     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
     while ( eIt->more() )
-      elems.insert( elems.end(), eIt->next());
+      theElements.insert( theElements.end(), eIt->next() );
   }
-  else
-    elems = theElements;
 
   vector< TGroupOfElems > arrayOfGroups;
   TGroupOfElems groupOfElems;
   TMapOfNodeSet mapOfNodeSet;
 
-  TElemsSet::iterator elemIt = elems.begin();
-  for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
+  TIDSortedElemSet::iterator elemIt = theElements.begin();
+  for ( int i = 0; elemIt != theElements.end(); ++elemIt )
+  {
     const SMDS_MeshElement* curElem = *elemIt;
     SortableElement SE(curElem);
-    int ind = -1;
     // check uniqueness
     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
-    if( !(pp.second) ) {
+    if ( !pp.second ) { // one more coincident elem
       TMapOfNodeSet::iterator& itSE = pp.first;
-      ind = (*itSE).second;
-      arrayOfGroups[ind].push_back(curElem->GetID());
+      int ind = (*itSE).second;
+      arrayOfGroups[ind].push_back( curElem->GetID() );
     }
     else {
-      groupOfElems.clear();
-      groupOfElems.push_back(curElem->GetID());
-      arrayOfGroups.push_back(groupOfElems);
+      arrayOfGroups.push_back( groupOfElems );
+      arrayOfGroups.back().push_back( curElem->GetID() );
       i++;
     }
   }
 
+  groupOfElems.clear();
   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
-  for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
-    groupOfElems = *groupIt;
-    if ( groupOfElems.size() > 1 ) {
-      groupOfElems.sort();
-      theGroupsOfElementsID.push_back(groupOfElems);
+  for ( ; groupIt != arrayOfGroups.end(); ++groupIt )
+  {
+    if ( groupIt->size() > 1 ) {
+      //groupOfElems.sort(); -- theElements is sorted already
+      theGroupsOfElementsID.push_back( groupOfElems );
+      theGroupsOfElementsID.back().splice( theGroupsOfElementsID.back().end(), *groupIt );
     }
   }
 }
@@ -8248,82 +7885,13 @@ void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElemen
 
 void SMESH_MeshEditor::MergeEqualElements()
 {
-  set<const SMDS_MeshElement*> aMeshElements; /* empty input -
-                                                 to merge equal elements in the whole mesh */
+  TIDSortedElemSet aMeshElements; /* empty input ==
+                                     to merge equal elements in the whole mesh */
   TListOfListOfElementsID aGroupsOfElementsID;
   FindEqualElements(aMeshElements, aGroupsOfElementsID);
   MergeElements(aGroupsOfElementsID);
 }
 
-//=======================================================================
-//function : FindFaceInSet
-//purpose  : Return a face having linked nodes n1 and n2 and which is
-//           - not in avoidSet,
-//           - in elemSet provided that !elemSet.empty()
-//           i1 and i2 optionally returns indices of n1 and n2
-//=======================================================================
-
-const SMDS_MeshElement*
-SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
-                                const SMDS_MeshNode*    n2,
-                                const TIDSortedElemSet& elemSet,
-                                const TIDSortedElemSet& avoidSet,
-                                int*                    n1ind,
-                                int*                    n2ind)
-
-{
-  int i1, i2;
-  const SMDS_MeshElement* face = 0;
-
-  SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
-  //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
-  while ( invElemIt->more() && !face ) // loop on inverse faces of n1
-  {
-    //MESSAGE("in while ( invElemIt->more() && !face )");
-    const SMDS_MeshElement* elem = invElemIt->next();
-    if (avoidSet.count( elem ))
-      continue;
-    if ( !elemSet.empty() && !elemSet.count( elem ))
-      continue;
-    // index of n1
-    i1 = elem->GetNodeIndex( n1 );
-    // find a n2 linked to n1
-    int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
-    for ( int di = -1; di < 2 && !face; di += 2 )
-    {
-      i2 = (i1+di+nbN) % nbN;
-      if ( elem->GetNode( i2 ) == n2 )
-        face = elem;
-    }
-    if ( !face && elem->IsQuadratic())
-    {
-      // analysis for quadratic elements using all nodes
-      const SMDS_VtkFace* F =
-        dynamic_cast<const SMDS_VtkFace*>(elem);
-      if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
-      // use special nodes iterator
-      SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
-      const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
-      for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
-      {
-        const SMDS_MeshNode* n = cast2Node( anIter->next() );
-        if ( n1 == prevN && n2 == n )
-        {
-          face = elem;
-        }
-        else if ( n2 == prevN && n1 == n )
-        {
-          face = elem; swap( i1, i2 );
-        }
-        prevN = n;
-      }
-    }
-  }
-  if ( n1ind ) *n1ind = i1;
-  if ( n2ind ) *n2ind = i2;
-  return face;
-}
-
 //=======================================================================
 //function : findAdjacentFace
 //purpose  :
@@ -8336,7 +7904,7 @@ static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
   TIDSortedElemSet elemSet, avoidSet;
   if ( elem )
     avoidSet.insert ( elem );
-  return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
+  return SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet );
 }
 
 //=======================================================================
@@ -8452,7 +8020,7 @@ bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirst
         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
         // find one more free border
-        if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
+        if ( ! SMESH_MeshEditor::FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
           cNL->clear();
           cFL->clear();
         }
@@ -9415,7 +8983,7 @@ namespace
 
 //=======================================================================
 /*!
- * \brief Convert elements contained in a submesh to quadratic
+ * \brief Convert elements contained in a sub-mesh to quadratic
  * \return int - nb of checked elements
  */
 //=======================================================================
@@ -9434,14 +9002,49 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
   {
     nbElem++;
     const SMDS_MeshElement* elem = ElemItr->next();
-    if( !elem || elem->IsQuadratic() ) continue;
+    if( !elem ) continue;
 
+    // analyse a necessity of conversion
+    const SMDSAbs_ElementType aType = elem->GetType();
+    if ( aType < SMDSAbs_Edge || aType > SMDSAbs_Volume )
+      continue;
+    const SMDSAbs_EntityType aGeomType = elem->GetEntityType();
+    bool hasCentralNodes = false;
+    if ( elem->IsQuadratic() )
+    {
+      bool alreadyOK;
+      switch ( aGeomType ) {
+      case SMDSEntity_Quad_Triangle:
+      case SMDSEntity_Quad_Quadrangle:
+      case SMDSEntity_Quad_Hexa:
+        alreadyOK = !theHelper.GetIsBiQuadratic(); break;
+
+      case SMDSEntity_BiQuad_Triangle:
+      case SMDSEntity_BiQuad_Quadrangle:
+      case SMDSEntity_TriQuad_Hexa:
+        alreadyOK = theHelper.GetIsBiQuadratic();
+        hasCentralNodes = true;
+        break;
+      default:
+        alreadyOK = true;
+      }
+      // take into account already present modium nodes
+      switch ( aType ) {
+      case SMDSAbs_Volume:
+        theHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( elem )); break;
+      case SMDSAbs_Face:
+        theHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem )); break;
+      case SMDSAbs_Edge:
+        theHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( elem )); break;
+      default:;
+      }
+      if ( alreadyOK )
+        continue;
+    }
     // get elem data needed to re-create it
     //
-    const int id                        = elem->GetID();
-    const int nbNodes                   = elem->NbNodes();
-    const SMDSAbs_ElementType aType     = elem->GetType();
-    const SMDSAbs_EntityType  aGeomType = elem->GetEntityType();
+    const int id      = elem->GetID();
+    const int nbNodes = elem->NbCornerNodes();
     nodes.assign(elem->begin_nodes(), elem->end_nodes());
     if ( aGeomType == SMDSEntity_Polyhedra )
       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
@@ -9451,6 +9054,12 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
     // remove a linear element
     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
 
+    // remove central nodes of biquadratic elements (biquad->quad convertion)
+    if ( hasCentralNodes )
+      for ( size_t i = nbNodes * 2; i < nodes.size(); ++i )
+        if ( nodes[i]->NbInverseElements() == 0 )
+          GetMeshDS()->RemoveFreeNode( nodes[i], theSm, /*fromGroups=*/true );
+
     const SMDS_MeshElement* NewElem = 0;
 
     switch( aType )
@@ -9472,7 +9081,6 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
           break;
         default:
           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
-          continue;
         }
         break;
       }
@@ -9490,6 +9098,8 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
           break;
         case SMDSEntity_Hexa:
+        case SMDSEntity_Quad_Hexa:
+        case SMDSEntity_TriQuad_Hexa:
           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
           break;
@@ -9503,24 +9113,28 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
       continue;
     }
     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
-    if( NewElem )
+    if( NewElem && NewElem->getshapeId() < 1 )
       theSm->AddElement( NewElem );
   }
   return nbElem;
 }
-
 //=======================================================================
 //function : ConvertToQuadratic
 //purpose  :
 //=======================================================================
 
-void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
+void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad)
 {
   SMESHDS_Mesh* meshDS = GetMeshDS();
 
   SMESH_MesherHelper aHelper(*myMesh);
+
   aHelper.SetIsQuadratic( true );
+  aHelper.SetIsBiQuadratic( theToBiQuad );
+  aHelper.SetElementsOnShape(true);
+  aHelper.ToFixNodeParameters( true );
 
+  // convert elements assigned to sub-meshes
   int nbCheckedElems = 0;
   if ( myMesh->HasShapeToMesh() )
   {
@@ -9536,18 +9150,22 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
       }
     }
   }
+
+  // convert elements NOT assigned to sub-meshes
   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
-  if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
+  if ( nbCheckedElems < totalNbElems ) // not all elements are in sub-meshes
   {
+    aHelper.SetElementsOnShape(false);
     SMESHDS_SubMesh *smDS = 0;
+
+    // convert edges
     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
-    while(aEdgeItr->more())
+    while( aEdgeItr->more() )
     {
       const SMDS_MeshEdge* edge = aEdgeItr->next();
-      if(edge && !edge->IsQuadratic())
+      if ( !edge->IsQuadratic() )
       {
-        int id = edge->GetID();
-        //MESSAGE("edge->GetID() " << id);
+        int                  id = edge->GetID();
         const SMDS_MeshNode* n1 = edge->GetNode(0);
         const SMDS_MeshNode* n2 = edge->GetNode(1);
 
@@ -9556,15 +9174,39 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
       }
+      else
+      {
+        aHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( edge ));
+      }
     }
+
+    // convert faces
     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
-    while(aFaceItr->more())
+    while( aFaceItr->more() )
     {
       const SMDS_MeshFace* face = aFaceItr->next();
-      if(!face || face->IsQuadratic() ) continue;
+      if ( !face ) continue;
+      
+      const SMDSAbs_EntityType type = face->GetEntityType();
+      bool alreadyOK;
+      switch( type )
+      {
+      case SMDSEntity_Quad_Triangle:
+      case SMDSEntity_Quad_Quadrangle:
+        alreadyOK = !theToBiQuad;
+        aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
+        break;
+      case SMDSEntity_BiQuad_Triangle:
+      case SMDSEntity_BiQuad_Quadrangle:
+        alreadyOK = theToBiQuad;
+        aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
+        break;
+      default: alreadyOK = false;
+      }
+      if ( alreadyOK )
+        continue;
 
       const int id = face->GetID();
-      const SMDSAbs_EntityType type = face->GetEntityType();
       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
 
       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
@@ -9573,25 +9215,52 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
       switch( type )
       {
       case SMDSEntity_Triangle:
+      case SMDSEntity_Quad_Triangle:
+      case SMDSEntity_BiQuad_Triangle:
         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
+        if ( nodes.size() == 7 && nodes[6]->NbInverseElements() == 0 ) // rm a central node
+          GetMeshDS()->RemoveFreeNode( nodes[6], /*sm=*/0, /*fromGroups=*/true );
         break;
+
       case SMDSEntity_Quadrangle:
+      case SMDSEntity_Quad_Quadrangle:
+      case SMDSEntity_BiQuad_Quadrangle:
         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
+        if ( nodes.size() == 9 && nodes[8]->NbInverseElements() == 0 ) // rm a central node
+          GetMeshDS()->RemoveFreeNode( nodes[8], /*sm=*/0, /*fromGroups=*/true );
         break;
-      default:
+
+      default:;
         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
       }
       ReplaceElemInGroups( face, NewFace, GetMeshDS());
     }
+
+    // convert volumes
     vector<int> nbNodeInFaces;
     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
     while(aVolumeItr->more())
     {
       const SMDS_MeshVolume* volume = aVolumeItr->next();
-      if(!volume || volume->IsQuadratic() ) continue;
+      if ( !volume ) continue;
 
-      const int id = volume->GetID();
       const SMDSAbs_EntityType type = volume->GetEntityType();
+      if ( volume->IsQuadratic() )
+      {
+        bool alreadyOK;
+        switch ( type )
+        {
+        case SMDSEntity_Quad_Hexa:    alreadyOK = !theToBiQuad; break;
+        case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; break;
+        default:                      alreadyOK = true;
+        }
+        if ( alreadyOK )
+        {
+          aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume ));
+          continue;
+        }
+      }
+      const int id = volume->GetID();
       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
       if ( type == SMDSEntity_Polyhedra )
         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
@@ -9607,8 +9276,13 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
         break;
       case SMDSEntity_Hexa:
+      case SMDSEntity_Quad_Hexa:
+      case SMDSEntity_TriQuad_Hexa:
         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
+        for ( size_t i = 20; i < nodes.size(); ++i ) // rm central nodes
+          if ( nodes[i]->NbInverseElements() == 0 )
+            GetMeshDS()->RemoveFreeNode( nodes[i], /*sm=*/0, /*fromGroups=*/true );
         break;
       case SMDSEntity_Pyramid:
         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
@@ -9628,8 +9302,9 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
 
   if ( !theForce3d )
   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
-    aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
-    aHelper.FixQuadraticElements();
+    // aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
+    // aHelper.FixQuadraticElements(myError);
+    SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
   }
 }
 
@@ -9637,18 +9312,19 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
 /*!
  * \brief Makes given elements quadratic
  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
- *  \param theElements - elements to make quadratic 
+ *  \param theElements - elements to make quadratic
  */
 //================================================================================
 
 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
-                                          TIDSortedElemSet& theElements)
+                                          TIDSortedElemSet& theElements,
+                                          const bool        theToBiQuad)
 {
   if ( theElements.empty() ) return;
 
   // we believe that all theElements are of the same type
   const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
-  
+
   // get all nodes shared by theElements
   TIDSortedNodeSet allNodes;
   TIDSortedElemSet::iterator eIt = theElements.begin();
@@ -9666,25 +9342,36 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
     while ( invIt->more() )
     {
-      const SMDS_MeshElement* e = invIt->next();
+      const SMDS_MeshElement*      e = invIt->next();
+      const SMDSAbs_ElementType type = e->GetType();
       if ( e->IsQuadratic() )
       {
-        quadAdjacentElems[ e->GetType() ].insert( e );
-        continue;
-      }
-      if ( e->GetType() >= elemType )
-      {
-        continue; // same type of more complex linear element
+        quadAdjacentElems[ type ].insert( e );
+
+        bool alreadyOK;
+        switch ( e->GetEntityType() ) {
+        case SMDSEntity_Quad_Triangle:
+        case SMDSEntity_Quad_Quadrangle:
+        case SMDSEntity_Quad_Hexa:         alreadyOK = !theToBiQuad; break;
+        case SMDSEntity_BiQuad_Triangle:
+        case SMDSEntity_BiQuad_Quadrangle:
+        case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; break;
+        default:                           alreadyOK = true;
+        }
+        if ( alreadyOK )
+          continue;
       }
+      if ( type >= elemType )
+        continue; // same type or more complex linear element
 
-      if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
+      if ( !checkedAdjacentElems[ type ].insert( e ).second )
         continue; // e is already checked
 
       // check nodes
       bool allIn = true;
-      SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
+      SMDS_NodeIteratorPtr nodeIt = e->nodeIterator();
       while ( nodeIt->more() && allIn )
-        allIn = allNodes.count( cast2Node( nodeIt->next() ));
+        allIn = allNodes.count( nodeIt->next() );
       if ( allIn )
         theElements.insert(e );
     }
@@ -9692,6 +9379,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
 
   SMESH_MesherHelper helper(*myMesh);
   helper.SetIsQuadratic( true );
+  helper.SetIsBiQuadratic( theToBiQuad );
 
   // add links of quadratic adjacent elements to the helper
 
@@ -9714,26 +9402,51 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
     }
 
-  // make quadratic elements instead of linear ones
+  // make quadratic (or bi-tri-quadratic) elements instead of linear ones
 
-  SMESHDS_Mesh* meshDS = GetMeshDS();
+  SMESHDS_Mesh*  meshDS = GetMeshDS();
   SMESHDS_SubMesh* smDS = 0;
   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
   {
     const SMDS_MeshElement* elem = *eIt;
-    if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
-      continue;
 
-    const int id                   = elem->GetID();
+    bool alreadyOK;
+    int nbCentralNodes = 0;
+    switch ( elem->GetEntityType() ) {
+      // linear convertible
+    case SMDSEntity_Edge:
+    case SMDSEntity_Triangle:
+    case SMDSEntity_Quadrangle:
+    case SMDSEntity_Tetra:
+    case SMDSEntity_Pyramid:
+    case SMDSEntity_Hexa:
+    case SMDSEntity_Penta:             alreadyOK = false;       nbCentralNodes = 0; break;
+      // quadratic that can become bi-quadratic
+    case SMDSEntity_Quad_Triangle:
+    case SMDSEntity_Quad_Quadrangle:
+    case SMDSEntity_Quad_Hexa:         alreadyOK =!theToBiQuad; nbCentralNodes = 0; break;
+      // bi-quadratic
+    case SMDSEntity_BiQuad_Triangle:
+    case SMDSEntity_BiQuad_Quadrangle: alreadyOK = theToBiQuad; nbCentralNodes = 1; break;
+    case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; nbCentralNodes = 7; break;
+      // the rest
+    default:                           alreadyOK = true;
+    }
+    if ( alreadyOK ) continue;
+
     const SMDSAbs_ElementType type = elem->GetType();
+    const int                   id = elem->GetID();
+    const int              nbNodes = elem->NbCornerNodes();
     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
 
+    helper.SetSubShape( elem->getshapeId() );
+
     if ( !smDS || !smDS->Contains( elem ))
       smDS = meshDS->MeshElements( elem->getshapeId() );
     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
 
     SMDS_MeshElement * newElem = 0;
-    switch( nodes.size() )
+    switch( nbNodes )
     {
     case 4: // cases for most frequently used element types go first (for optimization)
       if ( type == SMDSAbs_Volume )
@@ -9764,12 +9477,19 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
     ReplaceElemInGroups( elem, newElem, meshDS);
     if( newElem && smDS )
       smDS->AddElement( newElem );
-  }
 
-  if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
+     // remove central nodes
+    for ( size_t i = nodes.size() - nbCentralNodes; i < nodes.size(); ++i )
+      if ( nodes[i]->NbInverseElements() == 0 )
+        meshDS->RemoveFreeNode( nodes[i], smDS, /*fromGroups=*/true );
+
+  } // loop on theElements
+
+  if ( !theForce3d )
   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
-    helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
-    helper.FixQuadraticElements();
+    // helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
+    // helper.FixQuadraticElements( myError );
+    SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
   }
 }
 
@@ -9786,6 +9506,8 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
 {
   int nbElem = 0;
   SMESHDS_Mesh* meshDS = GetMeshDS();
+  ElemFeatures elemType;
+  vector<const SMDS_MeshNode *> nodes;
 
   while( theItr->more() )
   {
@@ -9793,11 +9515,11 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
     nbElem++;
     if( elem && elem->IsQuadratic())
     {
-      int id                    = elem->GetID();
-      int nbCornerNodes         = elem->NbCornerNodes();
-      SMDSAbs_ElementType aType = elem->GetType();
+      // get elem data
+      int nbCornerNodes = elem->NbCornerNodes();
+      nodes.assign( elem->begin_nodes(), elem->end_nodes() );
 
-      vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
+      elemType.Init( elem, /*basicOnly=*/false ).SetID( elem->GetID() ).SetQuad( false );
 
       //remove a quadratic element
       if ( !theSm || !theSm->Contains( elem ))
@@ -9805,13 +9527,13 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
 
       // remove medium nodes
-      for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
+      for ( size_t i = nbCornerNodes; i < nodes.size(); ++i )
         if ( nodes[i]->NbInverseElements() == 0 )
           meshDS->RemoveFreeNode( nodes[i], theSm );
 
       // add a linear element
       nodes.resize( nbCornerNodes );
-      SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
+      SMDS_MeshElement * newElem = AddElement( nodes, elemType );
       ReplaceElemInGroups(elem, newElem, meshDS);
       if( theSm && newElem )
         theSm->AddElement( newElem );
@@ -9890,8 +9612,7 @@ void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
   }
 
   // replace given elements by linear ones
-  typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
-  SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
+  SMDS_ElemIteratorPtr elemIt = elemSetIterator( theElements );
   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
 
   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
@@ -9928,7 +9649,7 @@ void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
             const SMDS_MeshElement* eComplex = invIt2->next();
             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
             {
-              int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
+              int nbCommonNodes = SMESH_MeshAlgos::GetCommonNodes( e, eComplex ).size();
               if ( nbCommonNodes == e->NbNodes())
               {
                 complexFound = true;
@@ -9943,8 +9664,7 @@ void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
       }
     }
   }
-  elemIt = SMDS_ElemIteratorPtr
-    (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
+  elemIt = elemSetIterator( moreElemsToConvert );
   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
 }
 
@@ -10293,8 +10013,10 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
       //cout << "Side " << iSide << " ";
       //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
       // find a face by two link nodes
-      face[ iSide ] = FindFaceInSet( n1, n2, *faceSetPtr[ iSide ], avoidSet,
-                                     &iLinkNode[iSide][0], &iLinkNode[iSide][1] );
+      face[ iSide ] = SMESH_MeshAlgos::FindFaceInSet( n1, n2,
+                                                      *faceSetPtr[ iSide ], avoidSet,
+                                                      &iLinkNode[iSide][0],
+                                                      &iLinkNode[iSide][1] );
       if ( face[ iSide ])
       {
         //cout << " F " << face[ iSide]->GetID() <<endl;
@@ -10402,11 +10124,15 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
   if ( aResult != SEW_OK)
     return aResult;
 
-  list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
+  list< int > nodeIDsToRemove;
+  vector< const SMDS_MeshNode*> nodes;
+  ElemFeatures elemType;
+
   // loop on nodes replacement map
   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
-    if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
+    if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second )
+    {
       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
       nodeIDsToRemove.push_back( nToRemove->GetID() );
       // loop on elements sharing nToRemove
@@ -10415,11 +10141,10 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
         const SMDS_MeshElement* e = invElemIt->next();
         // get a new suite of nodes: make replacement
         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
-        vector< const SMDS_MeshNode*> nodes( nbNodes );
+        nodes.resize( nbNodes );
         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
         while ( nIt->more() ) {
-          const SMDS_MeshNode* n =
-            static_cast<const SMDS_MeshNode*>( nIt->next() );
+          const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nIt->next() );
           nnIt = nReplaceMap.find( n );
           if ( nnIt != nReplaceMap.end() ) {
             nbReplaced++;
@@ -10431,21 +10156,17 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
         //         elemIDsToRemove.push_back( e->GetID() );
         //       else
         if ( nbReplaced )
+        {
+          elemType.Init( e, /*basicOnly=*/false ).SetID( e->GetID() );
+          aMesh->RemoveElement( e );
+
+          if ( SMDS_MeshElement* newElem = this->AddElement( nodes, elemType ))
           {
-            SMDSAbs_ElementType etyp = e->GetType();
-            SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
-            if (newElem)
-              {
-                myLastCreatedElems.Append(newElem);
-                AddToSameGroups(newElem, e, aMesh);
-                int aShapeId = e->getshapeId();
-                if ( aShapeId )
-                  {
-                    aMesh->SetMeshElementOnShape( newElem, aShapeId );
-                  }
-              }
-            aMesh->RemoveElement(e);
+            AddToSameGroups( newElem, e, aMesh );
+            if ( int aShapeId = e->getshapeId() )
+              aMesh->SetMeshElementOnShape( newElem, aShapeId );
           }
+        }
       }
     }
 
@@ -10627,13 +10348,77 @@ SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
   return SEW_OK;
 }
 
+//================================================================================
+/*!
+ * \brief Create elements equal (on same nodes) to given ones
+ *  \param [in] theElements - a set of elems to duplicate. If it is empty, all
+ *              elements of the uppest dimension are duplicated.
+ */
+//================================================================================
+
+void SMESH_MeshEditor::DoubleElements( const TIDSortedElemSet& theElements )
+{
+  ClearLastCreated();
+  SMESHDS_Mesh* mesh = GetMeshDS();
+
+  // get an element type and an iterator over elements
+
+  SMDSAbs_ElementType type;
+  SMDS_ElemIteratorPtr elemIt;
+  vector< const SMDS_MeshElement* > allElems;
+  if ( theElements.empty() )
+  {
+    if ( mesh->NbNodes() == 0 )
+      return;
+    // get most complex type
+    SMDSAbs_ElementType types[SMDSAbs_NbElementTypes] = {
+      SMDSAbs_Volume, SMDSAbs_Face, SMDSAbs_Edge,
+      SMDSAbs_0DElement, SMDSAbs_Ball, SMDSAbs_Node
+    };
+    for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
+      if ( mesh->GetMeshInfo().NbElements( types[i] ))
+      {
+        type = types[i];
+        break;
+      }
+    // put all elements in the vector <allElems>
+    allElems.reserve( mesh->GetMeshInfo().NbElements( type ));
+    elemIt = mesh->elementsIterator( type );
+    while ( elemIt->more() )
+      allElems.push_back( elemIt->next());
+    elemIt = elemSetIterator( allElems );
+  }
+  else
+  {
+    type = (*theElements.begin())->GetType();
+    elemIt = elemSetIterator( theElements );
+  }
+
+  // duplicate elements
+
+  ElemFeatures elemType;
+
+  vector< const SMDS_MeshNode* > nodes;
+  while ( elemIt->more() )
+  {
+    const SMDS_MeshElement* elem = elemIt->next();
+    if ( elem->GetType() != type )
+      continue;
+
+    elemType.Init( elem, /*basicOnly=*/false );
+    nodes.assign( elem->begin_nodes(), elem->end_nodes() );
+
+    AddElement( nodes, elemType );
+  }
+}
+
 //================================================================================
 /*!
   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
   \param theElems - the list of elements (edges or faces) to be replicated
   The nodes for duplication could be found from these elements
   \param theNodesNot - list of nodes to NOT replicate
-  \param theAffectedElems - the list of elements (cells and edges) to which the 
+  \param theAffectedElems - the list of elements (cells and edges) to which the
   replicated nodes should be associated to.
   \return TRUE if operation has been completed successfully, FALSE otherwise
 */
@@ -10654,7 +10439,7 @@ bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
     return false;
 
   bool res = false;
-  std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
+  TNodeNodeMap anOldNodeToNewNode;
   // duplicate elements and nodes
   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
   // replce nodes by duplications
@@ -10674,16 +10459,18 @@ bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
 */
 //================================================================================
 
-bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
-                                    const TIDSortedElemSet& theElems,
-                                    const TIDSortedElemSet& theNodesNot,
-                                    std::map< const SMDS_MeshNode*,
-                                    const SMDS_MeshNode* >& theNodeNodeMap,
-                                    const bool theIsDoubleElem )
+bool SMESH_MeshEditor::doubleNodes(SMESHDS_Mesh*           theMeshDS,
+                                   const TIDSortedElemSet& theElems,
+                                   const TIDSortedElemSet& theNodesNot,
+                                   TNodeNodeMap&           theNodeNodeMap,
+                                   const bool              theIsDoubleElem )
 {
   MESSAGE("doubleNodes");
-  // iterate on through element and duplicate them (by nodes duplication)
+  // iterate through element and duplicate them (by nodes duplication)
   bool res = false;
+  std::vector<const SMDS_MeshNode*> newNodes;
+  ElemFeatures elemType;
+
   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
   for ( ;  elemItr != theElems.end(); ++elemItr )
   {
@@ -10691,22 +10478,25 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
     if (!anElem)
       continue;
 
-    bool isDuplicate = false;
     // duplicate nodes to duplicate element
-    std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
+    bool isDuplicate = false;
+    newNodes.resize( anElem->NbNodes() );
     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
     int ind = 0;
-    while ( anIter->more() ) 
-    { 
-
-      SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
-      SMDS_MeshNode* aNewNode = aCurrNode;
-      if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
-        aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
-      else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
+    while ( anIter->more() )
+    {
+      const SMDS_MeshNode* aCurrNode = static_cast<const SMDS_MeshNode*>( anIter->next() );
+      const SMDS_MeshNode*  aNewNode = aCurrNode;
+      TNodeNodeMap::iterator     n2n = theNodeNodeMap.find( aCurrNode );
+      if ( n2n != theNodeNodeMap.end() )
+      {
+        aNewNode = n2n->second;
+      }
+      else if ( theIsDoubleElem && !theNodesNot.count( aCurrNode ))
       {
         // duplicate node
         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
+        copyPosition( aCurrNode, aNewNode );
         theNodeNodeMap[ aCurrNode ] = aNewNode;
         myLastCreatedNodes.Append( aNewNode );
       }
@@ -10717,12 +10507,10 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
       continue;
 
     if ( theIsDoubleElem )
-      AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
+      AddElement( newNodes, elemType.Init( anElem, /*basicOnly=*/false ));
     else
-      {
-      MESSAGE("ChangeElementNodes");
-      theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
-      }
+      theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], newNodes.size() );
+
     res = true;
   }
   return res;
@@ -10732,14 +10520,14 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
 /*!
   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
   \param theNodes - identifiers of nodes to be doubled
-  \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
-         nodes. If list of element identifiers is empty then nodes are doubled but 
-         they not assigned to elements
+  \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
+  nodes. If list of element identifiers is empty then nodes are doubled but
+  they not assigned to elements
   \return TRUE if operation has been completed successfully, FALSE otherwise
 */
 //================================================================================
 
-bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
+bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
                                     const std::list< int >& theListOfModifiedElems )
 {
   MESSAGE("DoubleNodes");
@@ -10770,6 +10558,7 @@ bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
     if ( aNewNode )
     {
+      copyPosition( aNode, aNewNode );
       anOldNodeToNewNode[ aNode ] = aNewNode;
       myLastCreatedNodes.Append( aNewNode );
     }
@@ -10780,7 +10569,7 @@ bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
 
   std::list< int >::const_iterator anElemIter;
-  for ( anElemIter = theListOfModifiedElems.begin(); 
+  for ( anElemIter = theListOfModifiedElems.begin();
         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
   {
     int aCurr = *anElemIter;
@@ -10792,8 +10581,8 @@ bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
 
     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
     int ind = 0;
-    while ( anIter->more() ) 
-    { 
+    while ( anIter->more() )
+    {
       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
       {
@@ -10806,7 +10595,7 @@ bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
     anElemToNodes[ anElem ] = aNodeArr;
   }
 
-  // Change nodes of elements  
+  // Change nodes of elements
 
   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
     anElemToNodesIter = anElemToNodes.begin();
@@ -10871,15 +10660,12 @@ namespace {
     }
     void Perform(const gp_Pnt& aPnt, double theTol)
     {
+      theTol *= theTol;
       _state = TopAbs_OUT;
       _extremum.Perform(aPnt);
       if ( _extremum.IsDone() )
         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
-#if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
-#else
-          _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
-#endif
     }
     TopAbs_State State() const
     {
@@ -10888,6 +10674,173 @@ namespace {
   };
 }
 
+//================================================================================
+/*!
+  \brief Identify the elements that will be affected by node duplication (actual duplication is not performed).
+  This method is the first step of DoubleNodeElemGroupsInRegion.
+  \param theElems - list of groups of elements (edges or faces) to be replicated
+  \param theNodesNot - list of groups of nodes not to replicated
+  \param theShape - shape to detect affected elements (element which geometric center
+         located on or inside shape). If the shape is null, detection is done on faces orientations
+         (select elements with a gravity center on the side given by faces normals).
+         This mode (null shape) is faster, but works only when theElems are faces, with coherents orientations.
+         The replicated nodes should be associated to affected elements.
+  \return groups of affected elements
+  \sa DoubleNodeElemGroupsInRegion()
+ */
+//================================================================================
+
+bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
+                                                   const TIDSortedElemSet& theNodesNot,
+                                                   const TopoDS_Shape&     theShape,
+                                                   TIDSortedElemSet&       theAffectedElems)
+{
+  if ( theShape.IsNull() )
+  {
+    std::set<const SMDS_MeshNode*> alreadyCheckedNodes;
+    std::set<const SMDS_MeshElement*> alreadyCheckedElems;
+    std::set<const SMDS_MeshElement*> edgesToCheck;
+    alreadyCheckedNodes.clear();
+    alreadyCheckedElems.clear();
+    edgesToCheck.clear();
+
+    // --- iterates on elements to be replicated and get elements by back references from their nodes
+
+    TIDSortedElemSet::const_iterator elemItr = theElems.begin();
+    int ielem;
+    for ( ielem=1;  elemItr != theElems.end(); ++elemItr )
+    {
+      SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
+      if (!anElem || (anElem->GetType() != SMDSAbs_Face))
+        continue;
+      gp_XYZ normal;
+      SMESH_MeshAlgos::FaceNormal( anElem, normal, /*normalized=*/true );
+      MESSAGE("element " << ielem++ <<  " normal " << normal.X() << " " << normal.Y() << " " << normal.Z());
+      std::set<const SMDS_MeshNode*> nodesElem;
+      nodesElem.clear();
+      SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
+      while ( nodeItr->more() )
+      {
+        const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
+        nodesElem.insert(aNode);
+      }
+      std::set<const SMDS_MeshNode*>::iterator nodit = nodesElem.begin();
+      for (; nodit != nodesElem.end(); nodit++)
+      {
+        MESSAGE("  noeud ");
+        const SMDS_MeshNode* aNode = *nodit;
+        if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
+          continue;
+        if (alreadyCheckedNodes.find(aNode) != alreadyCheckedNodes.end())
+          continue;
+        alreadyCheckedNodes.insert(aNode);
+        SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
+        while ( backElemItr->more() )
+        {
+          MESSAGE("    backelem ");
+          const SMDS_MeshElement* curElem = backElemItr->next();
+          if (alreadyCheckedElems.find(curElem) != alreadyCheckedElems.end())
+            continue;
+          if (theElems.find(curElem) != theElems.end())
+            continue;
+          alreadyCheckedElems.insert(curElem);
+          double x=0, y=0, z=0;
+          int nb = 0;
+          SMDS_ElemIteratorPtr nodeItr2 = curElem->nodesIterator();
+          while ( nodeItr2->more() )
+          {
+            const SMDS_MeshNode* anotherNode = cast2Node(nodeItr2->next());
+            x += anotherNode->X();
+            y += anotherNode->Y();
+            z += anotherNode->Z();
+            nb++;
+          }
+          gp_XYZ p;
+          p.SetCoord( x/nb -aNode->X(),
+                      y/nb -aNode->Y(),
+                      z/nb -aNode->Z() );
+          MESSAGE("      check " << p.X() << " " << p.Y() << " " << p.Z());
+          if (normal*p > 0)
+          {
+            MESSAGE("    --- inserted")
+            theAffectedElems.insert( curElem );
+          }
+          else if (curElem->GetType() == SMDSAbs_Edge)
+            edgesToCheck.insert(curElem);
+        }
+      }
+    }
+    // --- add also edges lying on the set of faces (all nodes in alreadyCheckedNodes)
+    std::set<const SMDS_MeshElement*>::iterator eit = edgesToCheck.begin();
+    for( ; eit != edgesToCheck.end(); eit++)
+    {
+      bool onside = true;
+      const SMDS_MeshElement* anEdge = *eit;
+      SMDS_ElemIteratorPtr nodeItr = anEdge->nodesIterator();
+      while ( nodeItr->more() )
+      {
+        const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
+        if (alreadyCheckedNodes.find(aNode) == alreadyCheckedNodes.end())
+        {
+          onside = false;
+          break;
+        }
+      }
+      if (onside)
+      {
+        MESSAGE("    --- edge onside inserted")
+        theAffectedElems.insert(anEdge);
+      }
+    }
+  }
+  else
+  {
+    const double aTol = Precision::Confusion();
+    auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
+    auto_ptr<_FaceClassifier>              aFaceClassifier;
+    if ( theShape.ShapeType() == TopAbs_SOLID )
+    {
+      bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
+      bsc3d->PerformInfinitePoint(aTol);
+    }
+    else if (theShape.ShapeType() == TopAbs_FACE )
+    {
+      aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
+    }
+
+    // iterates on indicated elements and get elements by back references from their nodes
+    TIDSortedElemSet::const_iterator elemItr = theElems.begin();
+    int ielem;
+    for ( ielem = 1;  elemItr != theElems.end(); ++elemItr )
+    {
+      MESSAGE("element " << ielem++);
+      SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
+      if (!anElem)
+        continue;
+      SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
+      while ( nodeItr->more() )
+      {
+        MESSAGE("  noeud ");
+        const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
+        if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
+          continue;
+        SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
+        while ( backElemItr->more() )
+        {
+          MESSAGE("    backelem ");
+          const SMDS_MeshElement* curElem = backElemItr->next();
+          if ( curElem && theElems.find(curElem) == theElems.end() &&
+              ( bsc3d.get() ?
+                isInside( curElem, *bsc3d, aTol ) :
+                isInside( curElem, *aFaceClassifier, aTol )))
+            theAffectedElems.insert( curElem );
+        }
+      }
+    }
+  }
+  return true;
+}
+
 //================================================================================
 /*!
   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
@@ -10969,23 +10922,34 @@ double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const
   gp_Vec v2(p0, g2);
   gp_Vec n1 = vref.Crossed(v1);
   gp_Vec n2 = vref.Crossed(v2);
-  return n2.AngleWithRef(n1, vref);
+  try {
+    return n2.AngleWithRef(n1, vref);
+  }
+  catch ( Standard_Failure ) {
+  }
+  return Max( v1.Magnitude(), v2.Magnitude() );
 }
 
 /*!
  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
- * The list of groups must describe a partition of the mesh volumes.
- * The nodes of the internal faces at the boundaries of the groups are doubled.
- * In option, the internal faces are replaced by flat elements.
- * Triangles are transformed in prisms, and quadrangles in hexahedrons.
- * The flat elements are stored in groups of volumes.
- * @param theElems - list of groups of volumes, where a group of volume is a set of
- * SMDS_MeshElements sorted by Id.
- * @param createJointElems - if TRUE, create the elements
- * @return TRUE if operation has been completed successfully, FALSE otherwise
+ *  The list of groups must contain at least two groups. The groups have to be disjoint: no common element into two different groups.
+ * The nodes of the internal faces at the boundaries of the groups are doubled. Optionally, the internal faces are replaced by flat elements.
+ * Triangles are transformed into prisms, and quadrangles into hexahedrons.
+ * The flat elements are stored in groups of volumes. These groups are named according to the position of the group in the list:
+ * the group j_n_p is the group of the flat elements that are built between the group #n and the group #p in the list.
+ * If there is no shared faces between the group #n and the group #p in the list, the group j_n_p is not created.
+ * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
+ * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
+ * \param theElems - list of groups of volumes, where a group of volume is a set of
+ *        SMDS_MeshElements sorted by Id.
+ * \param createJointElems - if TRUE, create the elements
+ * \param onAllBoundaries - if TRUE, the nodes and elements are also created on
+ *        the boundary between \a theDomains and the rest mesh
+ * \return TRUE if operation has been completed successfully, FALSE otherwise
  */
 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
-                                                     bool createJointElems)
+                                                     bool                                 createJointElems,
+                                                     bool                                 onAllBoundaries)
 {
   MESSAGE("----------------------------------------------");
   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
@@ -11012,20 +10976,51 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
   std::set<int> emptySet;
   emptyMap.clear();
 
-  for (int idom = 0; idom < theElems.size(); idom++)
+  MESSAGE(".. Number of domains :"<<theElems.size());
+
+  TIDSortedElemSet theRestDomElems;
+  const int iRestDom  = -1;
+  const int idom0     = onAllBoundaries ? iRestDom : 0;
+  const int nbDomains = theElems.size();
+
+  // Check if the domains do not share an element
+  for (int idom = 0; idom < nbDomains-1; idom++)
+    {
+//       MESSAGE("... Check of domain #" << idom);
+      const TIDSortedElemSet& domain = theElems[idom];
+      TIDSortedElemSet::const_iterator elemItr = domain.begin();
+      for (; elemItr != domain.end(); ++elemItr)
+        {
+          const SMDS_MeshElement* anElem = *elemItr;
+          int idombisdeb = idom + 1 ;
+          for (int idombis = idombisdeb; idombis < theElems.size(); idombis++) // check if the element belongs to a domain further in the list
+          {
+            const TIDSortedElemSet& domainbis = theElems[idombis];
+            if ( domainbis.count(anElem) )
+            {
+              MESSAGE(".... Domain #" << idom);
+              MESSAGE(".... Domain #" << idombis);
+              throw SALOME_Exception("The domains are not disjoint.");
+              return false ;
+            }
+          }
+        }
+    }
+
+  for (int idom = 0; idom < nbDomains; idom++)
     {
 
       // --- build a map (face to duplicate --> volume to modify)
       //     with all the faces shared by 2 domains (group of elements)
       //     and corresponding volume of this domain, for each shared face.
-      //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
+      //     a volume has a face shared by 2 domains if it has a neighbor which is not in his domain.
 
-      //MESSAGE("Domain " << idom);
+      MESSAGE("... Neighbors of domain #" << idom);
       const TIDSortedElemSet& domain = theElems[idom];
       TIDSortedElemSet::const_iterator elemItr = domain.begin();
       for (; elemItr != domain.end(); ++elemItr)
         {
-          SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
+          const SMDS_MeshElement* anElem = *elemItr;
           if (!anElem)
             continue;
           int vtkId = anElem->getVtkId();
@@ -11038,17 +11033,31 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
             {
               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
-              if (! domain.count(elem)) // neighbor is in another domain : face is shared
+              if (elem && ! domain.count(elem)) // neighbor is in another domain : face is shared
                 {
-                  DownIdType face(downIds[n], downTypes[n]);
-                  if (!faceDomains.count(face))
-                    faceDomains[face] = emptyMap; // create an empty entry for face
-                  if (!faceDomains[face].count(idom))
+                  bool ok = false ;
+                  for (int idombis = 0; idombis < theElems.size() && !ok; idombis++) // check if the neighbor belongs to another domain of the list
+                  {
+                    // MESSAGE("Domain " << idombis);
+                    const TIDSortedElemSet& domainbis = theElems[idombis];
+                    if ( domainbis.count(elem)) ok = true ; // neighbor is in a correct domain : face is kept
+                  }
+                  if ( ok || onAllBoundaries ) // the characteristics of the face is stored
+                  {
+                    DownIdType face(downIds[n], downTypes[n]);
+                    if (!faceDomains[face].count(idom))
+                      {
+                        faceDomains[face][idom] = vtkId; // volume associated to face in this domain
+                        celldom[vtkId] = idom;
+                        //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
+                      }
+                    if ( !ok )
                     {
-                      faceDomains[face][idom] = vtkId; // volume associated to face in this domain
-                      celldom[vtkId] = idom;
-                      //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
+                      theRestDomElems.insert( elem );
+                      faceDomains[face][iRestDom] = neighborsVtkIds[n];
+                      celldom[neighborsVtkIds[n]] = iRestDom;
                     }
+                  }
                 }
             }
         }
@@ -11061,14 +11070,14 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
   //     explore the nodes of the face and see if they belong to a cell in the domain,
   //     which has only a node or an edge on the border (not a shared face)
 
-  for (int idomain = 0; idomain < theElems.size(); idomain++)
+  for (int idomain = idom0; idomain < nbDomains; idomain++)
     {
       //MESSAGE("Domain " << idomain);
-      const TIDSortedElemSet& domain = theElems[idomain];
+      const TIDSortedElemSet& domain = (idomain == iRestDom) ? theRestDomElems : theElems[idomain];
       itface = faceDomains.begin();
       for (; itface != faceDomains.end(); ++itface)
         {
-          std::map<int, int> domvol = itface->second;
+          const std::map<int, int>& domvol = itface->second;
           if (!domvol.count(idomain))
             continue;
           DownIdType face = itface->first;
@@ -11081,8 +11090,6 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
             {
               int oldId = *itn;
               //MESSAGE("     node " << oldId);
-              std::set<int> cells;
-              cells.clear();
               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
               for (int i=0; i<l.ncells; i++)
                 {
@@ -11099,8 +11106,6 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
                                 //no cells created after BuildDownWardConnectivity
                     }
                   DownIdType aCell(downId, vtkType);
-                  if (celldom.count(vtkId))
-                    continue;
                   cellDomains[aCell][idomain] = vtkId;
                   celldom[vtkId] = idomain;
                   //MESSAGE("       cell " << vtkId << " domain " << idomain);
@@ -11121,12 +11126,13 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
   std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
   std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
 
-  for (int idomain = 0; idomain < theElems.size(); idomain++)
+  MESSAGE(".. Duplication of the nodes");
+  for (int idomain = idom0; idomain < nbDomains; idomain++)
     {
       itface = faceDomains.begin();
       for (; itface != faceDomains.end(); ++itface)
         {
-          std::map<int, int> domvol = itface->second;
+          const std::map<int, int>& domvol = itface->second;
           if (!domvol.count(idomain))
             continue;
           DownIdType face = itface->first;
@@ -11134,17 +11140,16 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
           std::set<int> oldNodes;
           oldNodes.clear();
           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
-          bool isMultipleDetected = false;
           std::set<int>::iterator itn = oldNodes.begin();
           for (; itn != oldNodes.end(); ++itn)
             {
               int oldId = *itn;
-              //MESSAGE("     node " << oldId);
-              if (!nodeDomains.count(oldId))
-                nodeDomains[oldId] = emptyMap; // create an empty entry for node
               if (nodeDomains[oldId].empty())
-                nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
-              std::map<int, int>::iterator itdom = domvol.begin();
+                {
+                  nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
+                  //MESSAGE("-+-+-b     oldNode " << oldId << " domain " << idomain);
+                }
+              std::map<int, int>::const_iterator itdom = domvol.begin();
               for (; itdom != domvol.end(); ++itdom)
                 {
                   int idom = itdom->first;
@@ -11155,7 +11160,6 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
                         {
                           vector<int> orderedDoms;
                           //MESSAGE("multiple node " << oldId);
-                          isMultipleDetected =true;
                           if (mutipleNodes.count(oldId))
                             orderedDoms = mutipleNodes[oldId];
                           else
@@ -11173,18 +11177,39 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
                         }
                       double *coords = grid->GetPoint(oldId);
                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
+                      copyPosition( meshDS->FindNodeVtk( oldId ), newNode );
                       int newId = newNode->getVtkId();
                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
-                      //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
-                    }
-                  if (nodeDomains[oldId].size() >= 3)
-                    {
-                      //MESSAGE("confirm multiple node " << oldId);
-                      isMultipleDetected =true;
+                      //MESSAGE("-+-+-c     oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
                     }
                 }
             }
-          if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
+        }
+    }
+
+  MESSAGE(".. Creation of elements");
+  for (int idomain = idom0; idomain < nbDomains; idomain++)
+    {
+      itface = faceDomains.begin();
+      for (; itface != faceDomains.end(); ++itface)
+        {
+          std::map<int, int> domvol = itface->second;
+          if (!domvol.count(idomain))
+            continue;
+          DownIdType face = itface->first;
+          //MESSAGE(" --- face " << face.cellId);
+          std::set<int> oldNodes;
+          oldNodes.clear();
+          grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
+          int nbMultipleNodes = 0;
+          std::set<int>::iterator itn = oldNodes.begin();
+          for (; itn != oldNodes.end(); ++itn)
+            {
+              int oldId = *itn;
+              if (mutipleNodes.count(oldId))
+                nbMultipleNodes++;
+            }
+          if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains
             {
               //MESSAGE("multiple Nodes detected on a shared face");
               int downId = itface->first.cellId;
@@ -11198,7 +11223,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
                     if (mutipleNodes.count(nodes[i]))
                       if (!mutipleNodesToFace.count(nodes[i]))
                         mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
-               }
+                }
               else // shared face (between two volumes)
                 {
                   int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
@@ -11212,9 +11237,12 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
                         {
                           vector<int> vn0 = mutipleNodes[nodes[0]];
                           vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
-                          sort( vn0.begin(), vn0.end() );
-                          sort( vn1.begin(), vn1.end() );
-                          if (vn0 == vn1)
+                          vector<int> doms;
+                          for (int i0 = 0; i0 < vn0.size(); i0++)
+                            for (int i1 = 0; i1 < vn1.size(); i1++)
+                              if (vn0[i0] == vn1[i1])
+                                doms.push_back(vn0[i0]);
+                          if (doms.size() >2)
                             {
                               //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
                               double *coords = grid->GetPoint(nodes[0]);
@@ -11226,14 +11254,15 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
                               map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
                               map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
                               int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
-                              for (int id=0; id < vn0.size(); id++)
+                              for (int id=0; id < doms.size(); id++)
                                 {
-                                  int idom = vn0[id];
+                                  int idom = doms[id];
+                                  const TIDSortedElemSet& domain = (idom == iRestDom) ? theRestDomElems : theElems[idom];
                                   for (int ivol=0; ivol<nbvol; ivol++)
                                     {
                                       int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
                                       SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
-                                      if (theElems[idom].count(elem))
+                                      if (domain.count(elem))
                                         {
                                           SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
                                           domvol[idom] = svol;
@@ -11289,8 +11318,17 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
   std::map<int, std::map<long,int> > nodeQuadDomains;
   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
 
+  MESSAGE(".. Creation of elements: simple junction");
   if (createJointElems)
     {
+      int idg;
+      string joints2DName = "joints2D";
+      mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg);
+      SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
+      string joints3DName = "joints3D";
+      mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg);
+      SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
+
       itface = faceDomains.begin();
       for (; itface != faceDomains.end(); ++itface)
         {
@@ -11314,13 +11352,16 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
             grpname << dom1 << "_" << dom2;
           else
             grpname << dom2 << "_" << dom1;
-          int idg;
           string namegrp = grpname.str();
           if (!mapOfJunctionGroups.count(namegrp))
             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
           if (sgrp)
             sgrp->Add(vol->GetID());
+          if (vol->GetType() == SMDSAbs_Volume)
+            joints3DGrp->Add(vol->GetID());
+          else if (vol->GetType() == SMDSAbs_Face)
+            joints2DGrp->Add(vol->GetID());
         }
     }
 
@@ -11328,6 +11369,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
   //     iterate on mutipleNodesToFace
   //     iterate on edgesMultiDomains
 
+  MESSAGE(".. Creation of elements: multiple junction");
   if (createJointElems)
     {
       // --- iterate on mutipleNodesToFace
@@ -11374,11 +11416,8 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
 
-              stringstream grpname;
-              grpname << "mj_";
-              grpname << 0 << "_" << 0;
               int idg;
-              string namegrp = grpname.str();
+              string namegrp = "jointsMultiples";
               if (!mapOfJunctionGroups.count(namegrp))
                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
@@ -11387,7 +11426,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
             }
           else
             {
-              MESSAGE("Quadratic multiple joints not implemented");
+              INFOS("Quadratic multiple joints not implemented");
               // TODO quadratic nodes
             }
         }
@@ -11403,7 +11442,8 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
   faceOrEdgeDom.clear();
   feDom.clear();
 
-  for (int idomain = 0; idomain < theElems.size(); idomain++)
+  MESSAGE(".. Modification of elements");
+  for (int idomain = idom0; idomain < nbDomains; idomain++)
     {
       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
       for (; itnod != nodeDomains.end(); ++itnod)
@@ -11476,6 +11516,14 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
         }
     }
 
+  // Remove empty groups (issue 0022812)
+  std::map<std::string, SMESH_Group*>::iterator name_group = mapOfJunctionGroups.begin();
+  for ( ; name_group != mapOfJunctionGroups.end(); ++name_group )
+  {
+    if ( name_group->second && name_group->second->GetGroupDS()->IsEmpty() )
+      myMesh->RemoveGroup( name_group->second->GetGroupDS()->GetID() );
+  }
+
   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
   grid->BuildLinks();
 
@@ -11543,6 +11591,7 @@ bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSort
               if (!clonedNodes.count(node))
                 {
                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
+                  copyPosition( node, clone );
                   clonedNodes[node] = clone;
                 }
               else
@@ -11559,6 +11608,7 @@ bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSort
                   if (!intermediateNodes.count(node))
                     {
                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
+                      copyPosition( node, inter );
                       intermediateNodes[node] = inter;
                     }
                   else
@@ -11645,6 +11695,537 @@ bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSort
   return true;
 }
 
+/*!
+ *  \brief identify all the elements around a geom shape, get the faces delimiting the hole
+ *  Build groups of volume to remove, groups of faces to replace on the skin of the object,
+ *  groups of faces to remove inside the object, (idem edges).
+ *  Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape)
+ */
+void SMESH_MeshEditor::CreateHoleSkin(double radius,
+                                      const TopoDS_Shape& theShape,
+                                      SMESH_NodeSearcher* theNodeSearcher,
+                                      const char* groupName,
+                                      std::vector<double>&   nodesCoords,
+                                      std::vector<std::vector<int> >& listOfListOfNodes)
+{
+  MESSAGE("--------------------------------");
+  MESSAGE("SMESH_MeshEditor::CreateHoleSkin");
+  MESSAGE("--------------------------------");
+
+  // --- zone of volumes to remove is given :
+  //     1 either by a geom shape (one or more vertices) and a radius,
+  //     2 either by a group of nodes (representative of the shape)to use with the radius,
+  //     3 either by a group of nodes where all the elements build on one of this nodes are to remove,
+  //     In the case 2, the group of nodes is an external group of nodes from another mesh,
+  //     In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter),
+  //     defined by it's name.
+
+  SMESHDS_GroupBase* groupDS = 0;
+  SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups();
+  while ( groupIt->more() )
+    {
+      groupDS = 0;
+      SMESH_Group * group = groupIt->next();
+      if ( !group ) continue;
+      groupDS = group->GetGroupDS();
+      if ( !groupDS || groupDS->IsEmpty() ) continue;
+      std::string grpName = group->GetName();
+      //MESSAGE("grpName=" << grpName);
+      if (grpName == groupName)
+        break;
+      else
+        groupDS = 0;
+    }
+
+  bool isNodeGroup = false;
+  bool isNodeCoords = false;
+  if (groupDS)
+    {
+      if (groupDS->GetType() != SMDSAbs_Node)
+        return;
+      isNodeGroup = true;     // a group of nodes exists and it is in this mesh
+    }
+
+  if (nodesCoords.size() > 0)
+    isNodeCoords = true; // a list o nodes given by their coordinates
+  //MESSAGE("---" << isNodeGroup << " " << isNodeCoords);
+
+  // --- define groups to build
+
+  int idg; // --- group of SMDS volumes
+  string grpvName = groupName;
+  grpvName += "_vol";
+  SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
+  if (!grp)
+    {
+      MESSAGE("group not created " << grpvName);
+      return;
+    }
+  SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
+
+  int idgs; // --- group of SMDS faces on the skin
+  string grpsName = groupName;
+  grpsName += "_skin";
+  SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
+  if (!grps)
+    {
+      MESSAGE("group not created " << grpsName);
+      return;
+    }
+  SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
+
+  int idgi; // --- group of SMDS faces internal (several shapes)
+  string grpiName = groupName;
+  grpiName += "_internalFaces";
+  SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
+  if (!grpi)
+    {
+      MESSAGE("group not created " << grpiName);
+      return;
+    }
+  SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
+
+  int idgei; // --- group of SMDS faces internal (several shapes)
+  string grpeiName = groupName;
+  grpeiName += "_internalEdges";
+  SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
+  if (!grpei)
+    {
+      MESSAGE("group not created " << grpeiName);
+      return;
+    }
+  SMESHDS_Group *sgrpei = dynamic_cast<SMESHDS_Group*>(grpei->GetGroupDS());
+
+  // --- build downward connectivity
+
+  SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
+  meshDS->BuildDownWardConnectivity(true);
+  SMDS_UnstructuredGrid* grid = meshDS->getGrid();
+
+  // --- set of volumes detected inside
+
+  std::set<int> setOfInsideVol;
+  std::set<int> setOfVolToCheck;
+
+  std::vector<gp_Pnt> gpnts;
+  gpnts.clear();
+
+  if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
+    {
+      MESSAGE("group of nodes provided");
+      SMDS_ElemIteratorPtr elemIt = groupDS->GetElements();
+      while ( elemIt->more() )
+        {
+          const SMDS_MeshElement* elem = elemIt->next();
+          if (!elem)
+            continue;
+          const SMDS_MeshNode* node = dynamic_cast<const SMDS_MeshNode*>(elem);
+          if (!node)
+            continue;
+          SMDS_MeshElement* vol = 0;
+          SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume);
+          while (volItr->more())
+            {
+              vol = (SMDS_MeshElement*)volItr->next();
+              setOfInsideVol.insert(vol->getVtkId());
+              sgrp->Add(vol->GetID());
+            }
+        }
+    }
+  else if (isNodeCoords)
+    {
+      MESSAGE("list of nodes coordinates provided");
+      int i = 0;
+      int k = 0;
+      while (i < nodesCoords.size()-2)
+        {
+          double x = nodesCoords[i++];
+          double y = nodesCoords[i++];
+          double z = nodesCoords[i++];
+          gp_Pnt p = gp_Pnt(x, y ,z);
+          gpnts.push_back(p);
+          MESSAGE("TopoDS_Vertex " << k << " " << p.X() << " " << p.Y() << " " << p.Z());
+          k++;
+        }
+    }
+  else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius
+    {
+      MESSAGE("no group of nodes provided, using vertices from geom shape, and radius");
+      TopTools_IndexedMapOfShape vertexMap;
+      TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap );
+      gp_Pnt p = gp_Pnt(0,0,0);
+      if (vertexMap.Extent() < 1)
+        return;
+
+      for ( int i = 1; i <= vertexMap.Extent(); ++i )
+        {
+          const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i ));
+          p = BRep_Tool::Pnt(vertex);
+          gpnts.push_back(p);
+          MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z());
+        }
+    }
+
+  if (gpnts.size() > 0)
+    {
+      int nodeId = 0;
+      const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
+      if (startNode)
+        nodeId = startNode->GetID();
+      MESSAGE("nodeId " << nodeId);
+
+      double radius2 = radius*radius;
+      MESSAGE("radius2 " << radius2);
+
+      // --- volumes on start node
+
+      setOfVolToCheck.clear();
+      SMDS_MeshElement* startVol = 0;
+      SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
+      while (volItr->more())
+        {
+          startVol = (SMDS_MeshElement*)volItr->next();
+          setOfVolToCheck.insert(startVol->getVtkId());
+        }
+      if (setOfVolToCheck.empty())
+        {
+          MESSAGE("No volumes found");
+          return;
+        }
+
+      // --- starting with central volumes then their neighbors, check if they are inside
+      //     or outside the domain, until no more new neighbor volume is inside.
+      //     Fill the group of inside volumes
+
+      std::map<int, double> mapOfNodeDistance2;
+      mapOfNodeDistance2.clear();
+      std::set<int> setOfOutsideVol;
+      while (!setOfVolToCheck.empty())
+        {
+          std::set<int>::iterator it = setOfVolToCheck.begin();
+          int vtkId = *it;
+          MESSAGE("volume to check,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
+          bool volInside = false;
+          vtkIdType npts = 0;
+          vtkIdType* pts = 0;
+          grid->GetCellPoints(vtkId, npts, pts);
+          for (int i=0; i<npts; i++)
+            {
+              double distance2 = 0;
+              if (mapOfNodeDistance2.count(pts[i]))
+                {
+                  distance2 = mapOfNodeDistance2[pts[i]];
+                  MESSAGE("point " << pts[i] << " distance2 " << distance2);
+                }
+              else
+                {
+                  double *coords = grid->GetPoint(pts[i]);
+                  gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
+                  distance2 = 1.E40;
+                  for (int j=0; j<gpnts.size(); j++)
+                    {
+                      double d2 = aPoint.SquareDistance(gpnts[j]);
+                      if (d2 < distance2)
+                        {
+                          distance2 = d2;
+                          if (distance2 < radius2)
+                            break;
+                        }
+                    }
+                  mapOfNodeDistance2[pts[i]] = distance2;
+                  MESSAGE("  point "  << pts[i]  << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " <<  coords[2]);
+                }
+              if (distance2 < radius2)
+                {
+                  volInside = true; // one or more nodes inside the domain
+                  sgrp->Add(meshDS->fromVtkToSmds(vtkId));
+                  break;
+                }
+            }
+          if (volInside)
+            {
+              setOfInsideVol.insert(vtkId);
+              MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
+              int neighborsVtkIds[NBMAXNEIGHBORS];
+              int downIds[NBMAXNEIGHBORS];
+              unsigned char downTypes[NBMAXNEIGHBORS];
+              int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
+              for (int n = 0; n < nbNeighbors; n++)
+                if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n]))
+                  setOfVolToCheck.insert(neighborsVtkIds[n]);
+            }
+          else
+            {
+              setOfOutsideVol.insert(vtkId);
+              MESSAGE("  volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
+            }
+          setOfVolToCheck.erase(vtkId);
+        }
+    }
+
+  // --- for outside hexahedrons, check if they have more than one neighbor volume inside
+  //     If yes, add the volume to the inside set
+
+  bool addedInside = true;
+  std::set<int> setOfVolToReCheck;
+  while (addedInside)
+    {
+      MESSAGE(" --------------------------- re check");
+      addedInside = false;
+      std::set<int>::iterator itv = setOfInsideVol.begin();
+      for (; itv != setOfInsideVol.end(); ++itv)
+        {
+          int vtkId = *itv;
+          int neighborsVtkIds[NBMAXNEIGHBORS];
+          int downIds[NBMAXNEIGHBORS];
+          unsigned char downTypes[NBMAXNEIGHBORS];
+          int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
+          for (int n = 0; n < nbNeighbors; n++)
+            if (!setOfInsideVol.count(neighborsVtkIds[n]))
+              setOfVolToReCheck.insert(neighborsVtkIds[n]);
+        }
+      setOfVolToCheck = setOfVolToReCheck;
+      setOfVolToReCheck.clear();
+      while  (!setOfVolToCheck.empty())
+        {
+          std::set<int>::iterator it = setOfVolToCheck.begin();
+          int vtkId = *it;
+          if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON)
+            {
+              MESSAGE("volume to recheck,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
+              int countInside = 0;
+              int neighborsVtkIds[NBMAXNEIGHBORS];
+              int downIds[NBMAXNEIGHBORS];
+              unsigned char downTypes[NBMAXNEIGHBORS];
+              int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
+              for (int n = 0; n < nbNeighbors; n++)
+                if (setOfInsideVol.count(neighborsVtkIds[n]))
+                  countInside++;
+              MESSAGE("countInside " << countInside);
+              if (countInside > 1)
+                {
+                  MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
+                  setOfInsideVol.insert(vtkId);
+                  sgrp->Add(meshDS->fromVtkToSmds(vtkId));
+                  addedInside = true;
+                }
+              else
+                setOfVolToReCheck.insert(vtkId);
+            }
+          setOfVolToCheck.erase(vtkId);
+        }
+    }
+
+  // --- map of Downward faces at the boundary, inside the global volume
+  //     map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin)
+  //     fill group of SMDS faces inside the volume (when several volume shapes)
+  //     fill group of SMDS faces on the skin of the global volume (if skin)
+
+  std::map<DownIdType, int, DownIdCompare> boundaryFaces; // boundary faces inside the volume --> corresponding cell
+  std::map<DownIdType, int, DownIdCompare> skinFaces;     // faces on the skin of the global volume --> corresponding cell
+  std::set<int>::iterator it = setOfInsideVol.begin();
+  for (; it != setOfInsideVol.end(); ++it)
+    {
+      int vtkId = *it;
+      //MESSAGE("  vtkId " << vtkId  << " smdsId " << meshDS->fromVtkToSmds(vtkId));
+      int neighborsVtkIds[NBMAXNEIGHBORS];
+      int downIds[NBMAXNEIGHBORS];
+      unsigned char downTypes[NBMAXNEIGHBORS];
+      int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true);
+      for (int n = 0; n < nbNeighbors; n++)
+        {
+          int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n]));
+          if (neighborDim == 3)
+            {
+              if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary
+                {
+                  DownIdType face(downIds[n], downTypes[n]);
+                  boundaryFaces[face] = vtkId;
+                }
+              // if the face between to volumes is in the mesh, get it (internal face between shapes)
+              int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
+              if (vtkFaceId >= 0)
+                {
+                  sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId));
+                  // find also the smds edges on this face
+                  int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]);
+                  const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]);
+                  const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]);
+                  for (int i = 0; i < nbEdges; i++)
+                    {
+                      int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]);
+                      if (vtkEdgeId >= 0)
+                        sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId));
+                    }
+                }
+            }
+          else if (neighborDim == 2) // skin of the volume
+            {
+              DownIdType face(downIds[n], downTypes[n]);
+              skinFaces[face] = vtkId;
+              int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
+              if (vtkFaceId >= 0)
+                sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId));
+            }
+        }
+    }
+
+  // --- identify the edges constituting the wire of each subshape on the skin
+  //     define polylines with the nodes of edges, equivalent to wires
+  //     project polylines on subshapes, and partition, to get geom faces
+
+  std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
+  std::set<int> emptySet;
+  emptySet.clear();
+  std::set<int> shapeIds;
+
+  SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
+  while (itelem->more())
+    {
+      const SMDS_MeshElement *elem = itelem->next();
+      int shapeId = elem->getshapeId();
+      int vtkId = elem->getVtkId();
+      if (!shapeIdToVtkIdSet.count(shapeId))
+        {
+          shapeIdToVtkIdSet[shapeId] = emptySet;
+          shapeIds.insert(shapeId);
+        }
+      shapeIdToVtkIdSet[shapeId].insert(vtkId);
+    }
+
+  std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
+  std::set<DownIdType, DownIdCompare> emptyEdges;
+  emptyEdges.clear();
+
+  std::map<int, std::set<int> >::iterator itShape =  shapeIdToVtkIdSet.begin();
+  for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
+    {
+      int shapeId = itShape->first;
+      MESSAGE(" --- Shape ID --- "<< shapeId);
+      shapeIdToEdges[shapeId] = emptyEdges;
+
+      std::vector<int> nodesEdges;
+
+      std::set<int>::iterator its = itShape->second.begin();
+      for (; its != itShape->second.end(); ++its)
+        {
+          int vtkId = *its;
+          MESSAGE("     " << vtkId);
+          int neighborsVtkIds[NBMAXNEIGHBORS];
+          int downIds[NBMAXNEIGHBORS];
+          unsigned char downTypes[NBMAXNEIGHBORS];
+          int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
+          for (int n = 0; n < nbNeighbors; n++)
+            {
+              if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
+                continue;
+              int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
+              const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
+              if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
+                {
+                  DownIdType edge(downIds[n], downTypes[n]);
+                  if (!shapeIdToEdges[shapeId].count(edge))
+                    {
+                      shapeIdToEdges[shapeId].insert(edge);
+                      int vtkNodeId[3];
+                      int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId);
+                      nodesEdges.push_back(vtkNodeId[0]);
+                      nodesEdges.push_back(vtkNodeId[nbNodes-1]);
+                      MESSAGE("       --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1);
+                    }
+                }
+            }
+        }
+
+      std::list<int> order;
+      order.clear();
+      if (nodesEdges.size() > 0)
+        {
+          order.push_back(nodesEdges[0]); MESSAGE("       --- back " << order.back()+1); // SMDS id = VTK id + 1;
+          nodesEdges[0] = -1;
+          order.push_back(nodesEdges[1]); MESSAGE("       --- back " << order.back()+1);
+          nodesEdges[1] = -1; // do not reuse this edge
+          bool found = true;
+          while (found)
+            {
+              int nodeTofind = order.back(); // try first to push back
+              int i = 0;
+              for (i = 0; i<nodesEdges.size(); i++)
+                if (nodesEdges[i] == nodeTofind)
+                  break;
+              if (i == nodesEdges.size())
+                found = false; // no follower found on back
+              else
+                {
+                  if (i%2) // odd ==> use the previous one
+                    if (nodesEdges[i-1] < 0)
+                      found = false;
+                    else
+                      {
+                        order.push_back(nodesEdges[i-1]); MESSAGE("       --- back " << order.back()+1);
+                        nodesEdges[i-1] = -1;
+                      }
+                  else // even ==> use the next one
+                    if (nodesEdges[i+1] < 0)
+                      found = false;
+                    else
+                      {
+                        order.push_back(nodesEdges[i+1]); MESSAGE("       --- back " << order.back()+1);
+                        nodesEdges[i+1] = -1;
+                      }
+                }
+              if (found)
+                continue;
+              // try to push front
+              found = true;
+              nodeTofind = order.front(); // try to push front
+              for (i = 0; i<nodesEdges.size(); i++)
+                if (nodesEdges[i] == nodeTofind)
+                  break;
+              if (i == nodesEdges.size())
+                {
+                  found = false; // no predecessor found on front
+                  continue;
+                }
+              if (i%2) // odd ==> use the previous one
+                if (nodesEdges[i-1] < 0)
+                  found = false;
+                else
+                  {
+                    order.push_front(nodesEdges[i-1]); MESSAGE("       --- front " << order.front()+1);
+                    nodesEdges[i-1] = -1;
+                  }
+              else // even ==> use the next one
+                if (nodesEdges[i+1] < 0)
+                  found = false;
+                else
+                  {
+                    order.push_front(nodesEdges[i+1]); MESSAGE("       --- front " << order.front()+1);
+                    nodesEdges[i+1] = -1;
+                  }
+            }
+        }
+
+
+      std::vector<int> nodes;
+      nodes.push_back(shapeId);
+      std::list<int>::iterator itl = order.begin();
+      for (; itl != order.end(); itl++)
+        {
+          nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
+          MESSAGE("              ordered node " << nodes[nodes.size()-1]);
+        }
+      listOfListOfNodes.push_back(nodes);
+    }
+
+  //     partition geom faces with blocFissure
+  //     mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose)
+  //     mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose)
+
+  return;
+}
+
+
 //================================================================================
 /*!
  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
@@ -11659,7 +12240,8 @@ bool SMESH_MeshEditor::Make2DMeshFrom3D()
   SMESHDS_Mesh* aMesh = GetMeshDS();
   if (!aMesh)
     return false;
-  //bool res = false;
+
+  ElemFeatures faceType( SMDSAbs_Face );
   int nbFree = 0, nbExisted = 0, nbCreated = 0;
   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
   while(vIt->more())
@@ -11667,8 +12249,8 @@ bool SMESH_MeshEditor::Make2DMeshFrom3D()
     const SMDS_MeshVolume* volume = vIt->next();
     SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
     vTool.SetExternalNormal();
-    //const bool isPoly = volume->IsPoly();
     const int iQuad = volume->IsQuadratic();
+    faceType.SetQuad( iQuad );
     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
     {
       if (!vTool.IsFreeFace(iface))
@@ -11680,22 +12262,27 @@ bool SMESH_MeshEditor::Make2DMeshFrom3D()
       int inode = 0;
       for ( ; inode < nbFaceNodes; inode += iQuad+1)
         nodes.push_back(faceNodes[inode]);
-      if (iQuad) { // add medium nodes
+
+      if (iQuad) // add medium nodes
+      {
         for ( inode = 1; inode < nbFaceNodes; inode += 2)
           nodes.push_back(faceNodes[inode]);
         if ( nbFaceNodes == 9 ) // bi-quadratic quad
           nodes.push_back(faceNodes[8]);
       }
       // add new face based on volume nodes
-      if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
-        nbExisted++;
-        continue; // face already exsist
+      if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) )
+      {
+        nbExisted++; // face already exsist
+      }
+      else
+      {
+        AddElement( nodes, faceType.SetPoly( nbFaceNodes/(iQuad+1) > 4 ));
+        nbCreated++;
       }
-      AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
-      nbCreated++;
     }
   }
-  return ( nbFree==(nbExisted+nbCreated) );
+  return ( nbFree == ( nbExisted + nbCreated ));
 }
 
 namespace
@@ -11757,27 +12344,28 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
   SMDS_VolumeTool vTool;
   TIDSortedElemSet avoidSet;
   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
-  int inode;
+  size_t inode;
 
   typedef vector<const SMDS_MeshNode*> TConnectivity;
+  TConnectivity tgtNodes;
+  ElemFeatures elemKind( missType );
 
   SMDS_ElemIteratorPtr eIt;
-  if (elements.empty())
-    eIt = aMesh->elementsIterator(elemType);
-  else
-    eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
+  if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
+  else                  eIt = elemSetIterator( elements );
 
   while (eIt->more())
   {
     const SMDS_MeshElement* elem = eIt->next();
-    const int iQuad = elem->IsQuadratic();
+    const int              iQuad = elem->IsQuadratic();
+    elemKind.SetQuad( iQuad );
 
     // ------------------------------------------------------------------------------------
     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
     // ------------------------------------------------------------------------------------
     vector<const SMDS_MeshElement*> presentBndElems;
     vector<TConnectivity>           missingBndElems;
-    TConnectivity nodes;
+    TConnectivity nodes, elemNodes;
     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
     {
       vTool.SetExternalNormal();
@@ -11787,8 +12375,8 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
         if ( !vTool.IsFreeFace(iface, &otherVol) &&
              ( !aroundElements || elements.count( otherVol )))
           continue;
-        const int nbFaceNodes = vTool.NbFaceNodes(iface);
         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
+        const size_t nbFaceNodes = vTool.NbFaceNodes (iface);
         if ( missType == SMDSAbs_Edge ) // boundary edges
         {
           nodes.resize( 2+iQuad );
@@ -11807,10 +12395,10 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
         {
           nodes.clear();
           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
-            nodes.push_back( nn[inode] );
-          if (iQuad) // add medium nodes
+            nodes.push_back( nn[inode] ); // add corner nodes
+          if (iQuad)
             for ( inode = 1; inode < nbFaceNodes; inode += 2)
-              nodes.push_back( nn[inode] );
+              nodes.push_back( nn[inode] ); // add medium nodes
           int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
           if ( iCenter > 0 )
             nodes.push_back( vTool.GetNodes()[ iCenter ] );
@@ -11838,22 +12426,24 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
         }
       }
     }
-    else                     // elem is a face ------------------------------------------
+    else if ( elem->GetType() == SMDSAbs_Face ) // elem is a face ------------------------
     {
       avoidSet.clear(), avoidSet.insert( elem );
-      int nbNodes = elem->NbCornerNodes();
-      nodes.resize( 2 /*+ iQuad*/);
-      for ( int i = 0; i < nbNodes; i++ )
+      elemNodes.assign( SMDS_MeshElement::iterator( elem->interlacedNodesElemIterator() ),
+                        SMDS_MeshElement::iterator() );
+      elemNodes.push_back( elemNodes[0] );
+      nodes.resize( 2 + iQuad );
+      const int nbLinks = elem->NbCornerNodes();
+      for ( int i = 0, iN = 0; i < nbLinks; i++, iN += 1+iQuad )
       {
-        nodes[0] = elem->GetNode(i);
-        nodes[1] = elem->GetNode((i+1)%nbNodes);
-        if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
+        nodes[0] = elemNodes[iN];
+        nodes[1] = elemNodes[iN+1+iQuad];
+        if ( SMESH_MeshAlgos::FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
           continue; // not free link
 
-        //if ( iQuad )
-        //nodes[2] = elem->GetNode( i + nbNodes );
+        if ( iQuad ) nodes[2] = elemNodes[iN+1];
         if ( const SMDS_MeshElement* edge =
-             aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
+             aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
           presentBndElems.push_back( edge );
         else
           missingBndElems.push_back( nodes );
@@ -11866,17 +12456,17 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
     if ( targetMesh != myMesh )
       // instead of making a map of nodes in this mesh and targetMesh,
       // we create nodes with same IDs.
-      for ( int i = 0; i < missingBndElems.size(); ++i )
+      for ( size_t i = 0; i < missingBndElems.size(); ++i )
       {
         TConnectivity& srcNodes = missingBndElems[i];
-        TConnectivity  nodes( srcNodes.size() );
-        for ( inode = 0; inode < nodes.size(); ++inode )
-          nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
-        if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
+        tgtNodes.resize( srcNodes.size() );
+        for ( inode = 0; inode < srcNodes.size(); ++inode )
+          tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
+        if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( tgtNodes,
                                                                    missType,
                                                                    /*noMedium=*/false))
           continue;
-        tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
+        tgtEditor.AddElement( tgtNodes, elemKind.SetPoly( tgtNodes.size()/(iQuad+1) > 4 ));
         ++nbAddedBnd;
       }
     else
@@ -11887,16 +12477,16 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
                                                                    missType,
                                                                    /*noMedium=*/false))
           continue;
-        SMDS_MeshElement* elem = 
-          tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
-        ++nbAddedBnd;
+        SMDS_MeshElement* newElem = 
+          tgtEditor.AddElement( nodes, elemKind.SetPoly( nodes.size()/(iQuad+1) > 4 ));
+        nbAddedBnd += bool( newElem );
 
         // try to set a new element to a shape
         if ( myMesh->HasShapeToMesh() )
         {
           bool ok = true;
           set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
-          const int nbN = nodes.size() / (iQuad+1 );
+          const size_t nbN = nodes.size() / (iQuad+1 );
           for ( inode = 0; inode < nbN && ok; ++inode )
           {
             pair<int, TopAbs_ShapeEnum> i_stype =
@@ -11916,7 +12506,7 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
             }
           }
           if ( ok && mediumShapes.begin()->first == missShapeType )
-            aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
+            aMesh->SetMeshElementOnShape( newElem, mediumShapes.begin()->second );
         }
       }
 
@@ -11927,17 +12517,17 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
       for ( int i = 0 ; i < presentBndElems.size(); ++i )
       {
         const SMDS_MeshElement* e = presentBndElems[i];
-        TConnectivity nodes( e->NbNodes() );
+        tgtNodes.resize( e->NbNodes() );
         for ( inode = 0; inode < nodes.size(); ++inode )
-          nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
-        presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
+          tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
+        presentEditor->AddElement( tgtNodes, elemKind.Init( e ));
       }
     else // store present elements to add them to a group
       for ( int i = 0 ; i < presentBndElems.size(); ++i )
       {
-        presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
+        presentEditor->myLastCreatedElems.Append( presentBndElems[i] );
       }
-      
+
   } // loop on given elements
 
   // ---------------------------------------------
@@ -11957,20 +12547,60 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
   // -----------------------
   if ( toCopyElements && targetMesh != myMesh )
   {
-    if (elements.empty())
-      eIt = aMesh->elementsIterator(elemType);
-    else
-      eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
+    if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
+    else                  eIt = elemSetIterator( elements );
     while (eIt->more())
     {
       const SMDS_MeshElement* elem = eIt->next();
-      TConnectivity nodes( elem->NbNodes() );
-      for ( inode = 0; inode < nodes.size(); ++inode )
-        nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
-      tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
+      tgtNodes.resize( elem->NbNodes() );
+      for ( inode = 0; inode < tgtNodes.size(); ++inode )
+        tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
+      tgtEditor.AddElement( tgtNodes, elemKind.Init( elem ));
 
       tgtEditor.myLastCreatedElems.Clear();
     }
   }
   return nbAddedBnd;
 }
+
+//================================================================================
+/*!
+ * \brief Copy node position and set \a to node on the same geometry
+ */
+//================================================================================
+
+void SMESH_MeshEditor::copyPosition( const SMDS_MeshNode* from,
+                                     const SMDS_MeshNode* to )
+{
+  if ( !from || !to ) return;
+
+  SMDS_PositionPtr pos = from->GetPosition();
+  if ( !pos || from->getshapeId() < 1 ) return;
+
+  switch ( pos->GetTypeOfPosition() )
+  {
+  case SMDS_TOP_3DSPACE: break;
+
+  case SMDS_TOP_FACE:
+  {
+    const SMDS_FacePosition* fPos = static_cast< const SMDS_FacePosition* >( pos );
+    GetMeshDS()->SetNodeOnFace( to, from->getshapeId(),
+                                fPos->GetUParameter(), fPos->GetVParameter() );
+    break;
+  }
+  case SMDS_TOP_EDGE:
+  {
+    // WARNING: it is dangerous to set equal nodes on one EDGE!!!!!!!!
+    const SMDS_EdgePosition* ePos = static_cast< const SMDS_EdgePosition* >( pos );
+    GetMeshDS()->SetNodeOnEdge( to, from->getshapeId(), ePos->GetUParameter() );
+    break;
+  }
+  case SMDS_TOP_VERTEX:
+  {
+    GetMeshDS()->SetNodeOnVertex( to, from->getshapeId() );
+    break;
+  }
+  case SMDS_TOP_UNSPEC:
+  default:;
+  }
+}