Salome HOME
Merge branch 'V8_3_BR' into ngr/python3_dev
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
index 4e9a0f48d5a3c8bbcf8b1858684604b8883e01f7..1f343b1c4233af0670e82e8529895fbedee6afb6 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2016  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
 
 #include "SMESH_MeshEditor.hxx"
 
-#include "SMDS_FaceOfNodes.hxx"
-#include "SMDS_VolumeTool.hxx"
+#include "SMDS_Downward.hxx"
 #include "SMDS_EdgePosition.hxx"
+#include "SMDS_FaceOfNodes.hxx"
 #include "SMDS_FacePosition.hxx"
-#include "SMDS_SpacePosition.hxx"
-#include "SMDS_MeshGroup.hxx"
 #include "SMDS_LinearEdge.hxx"
-#include "SMDS_Downward.hxx"
+#include "SMDS_MeshGroup.hxx"
 #include "SMDS_SetIterator.hxx"
-
+#include "SMDS_SpacePosition.hxx"
+#include "SMDS_VolumeTool.hxx"
 #include "SMESHDS_Group.hxx"
 #include "SMESHDS_Mesh.hxx"
-
 #include "SMESH_Algo.hxx"
 #include "SMESH_ControlsDef.hxx"
 #include "SMESH_Group.hxx"
+#include "SMESH_Mesh.hxx"
 #include "SMESH_MeshAlgos.hxx"
 #include "SMESH_MesherHelper.hxx"
 #include "SMESH_OctreeNode.hxx"
@@ -50,6 +49,7 @@
 #include <Basics_OCCTVersion.hxx>
 
 #include "utilities.h"
+#include "chrono.hxx"
 
 #include <BRepAdaptor_Surface.hxx>
 #include <BRepBuilderAPI_MakeEdge.hxx>
@@ -72,6 +72,7 @@
 #include <TopTools_ListOfShape.hxx>
 #include <TopTools_SequenceOfShape.hxx>
 #include <TopoDS.hxx>
+#include <TopoDS_Edge.hxx>
 #include <TopoDS_Face.hxx>
 #include <TopoDS_Solid.hxx>
 #include <gp.hxx>
@@ -105,9 +106,11 @@ using namespace SMESH::Controls;
 
 namespace
 {
-  SMDS_ElemIteratorPtr elemSetIterator( const TIDSortedElemSet& elements )
+  template < class ELEM_SET >
+  SMDS_ElemIteratorPtr elemSetIterator( const ELEM_SET& elements )
   {
-    typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
+    typedef SMDS_SetIterator
+      < SMDS_pElement, typename ELEM_SET::const_iterator> TSetIterator;
     return SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
   }
 }
@@ -122,18 +125,64 @@ SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
 {
 }
 
+//================================================================================
+/*!
+ * \brief Return mesh DS
+ */
+//================================================================================
+
+SMESHDS_Mesh * SMESH_MeshEditor::GetMeshDS()
+{
+  return myMesh->GetMeshDS();
+}
+
+
 //================================================================================
 /*!
  * \brief Clears myLastCreatedNodes and myLastCreatedElems
  */
 //================================================================================
 
-void SMESH_MeshEditor::CrearLastCreated()
+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;
+}
 
 //=======================================================================
 /*!
@@ -143,18 +192,16 @@ void SMESH_MeshEditor::CrearLastCreated()
 
 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] );
@@ -187,14 +234,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] );
@@ -282,6 +336,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:
@@ -304,12 +368,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:;
@@ -324,10 +388,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() );
@@ -338,7 +400,7 @@ SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs
     else
       return 0;
   }
-  return AddElement( nodes, type, isPoly, ID );
+  return AddElement( nodes, features );
 }
 
 //=======================================================================
@@ -412,22 +474,27 @@ int SMESH_MeshEditor::Remove (const list< int >& theIDs,
 
 //================================================================================
 /*!
- * \brief Create 0D elements on all nodes of the given object except those
- *        nodes on which a 0D element already exists.
+ * \brief Create 0D elements on all nodes of the given object.
  *  \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
+ *  \param duplicateElements - to add one more 0D element to a node or not
  */
 //================================================================================
 
 void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements,
-                                                   TIDSortedElemSet&       all0DElems )
+                                                   TIDSortedElemSet&       all0DElems,
+                                                   const bool              duplicateElements )
 {
   SMDS_ElemIteratorPtr elemIt;
   if ( elements.empty() )
+  {
     elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node );
+  }
   else
+  {
     elemIt = elemSetIterator( elements );
+  }
 
   while ( elemIt->more() )
   {
@@ -437,12 +504,13 @@ void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& eleme
     {
       const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
       SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement );
-      if ( it0D->more() )
-        all0DElems.insert( it0D->next() );
-      else {
+      if ( duplicateElements || !it0D->more() )
+      {
         myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n ));
         all0DElems.insert( myLastCreatedElems.Last() );
       }
+      while ( it0D->more() )
+        all0DElems.insert( it0D->next() );
     }
   }
 }
@@ -506,14 +574,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;
 }
 
@@ -625,7 +691,6 @@ static bool getNodesFromTwoTria(const SMDS_MeshElement * theTria1,
 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
                                     const SMDS_MeshElement * theTria2 )
 {
-  MESSAGE("InverseDiag");
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
@@ -646,7 +711,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() ) {
@@ -672,15 +737,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
@@ -830,8 +895,6 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
-  MESSAGE( "::InverseDiag()" );
-
   const SMDS_MeshElement *tr1, *tr2;
   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
     return false;
@@ -953,8 +1016,6 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
-  MESSAGE( "::DeleteDiag()" );
-
   const SMDS_MeshElement *tr1, *tr2;
   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
     return false;
@@ -1047,7 +1108,6 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
 
 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
 {
-  MESSAGE("Reorient");
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
@@ -1089,12 +1149,12 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
   else // other elements
   {
     vector<const SMDS_MeshNode*> nodes( theElem->begin_nodes(), theElem->end_nodes() );
-    const std::vector<int>& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType );
+    const std::vector<int>& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType, nodes.size() );
     if ( interlace.empty() )
     {
-      std::reverse( nodes.begin(), nodes.end() ); // polygon
+      std::reverse( nodes.begin(), nodes.end() ); // obsolete, just in case
     }
-    else if ( interlace.size() > 1 )
+    else
     {
       SMDS_MeshCell::applyInterlace( interlace, nodes );
     }
@@ -1108,7 +1168,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 oriented according to
+ * \param theFace - one of \a theFaces that should be oriented according to
  *        \a theDirection and whose orientation defines orientation of other faces
  * \return number of reoriented faces.
  */
@@ -1162,7 +1222,7 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
     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
@@ -1233,6 +1293,92 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
   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 size_t 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 ( size_t 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 ( size_t 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  :
@@ -1374,7 +1520,7 @@ void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
   gp_XY  uv [9]; uv[8] = gp_XY(0,0);
   gp_XYZ xyz[9];
   vector< const SMDS_MeshNode* > nodes;
-  SMESHDS_SubMesh*               subMeshDS;
+  SMESHDS_SubMesh*               subMeshDS = 0;
   TopoDS_Face                    F;
   Handle(Geom_Surface)           surface;
   TopLoc_Location                loc;
@@ -1457,13 +1603,13 @@ void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
 
     // 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 ));
 
+    GetMeshDS()->RemoveFreeElement( quad, subMeshDS, /*fromGroups=*/false );
+
     for ( int i = 0; i < 4; ++i )
     {
       SMDS_MeshElement* tria = helper.AddFace( nodes[ i ],
@@ -1591,44 +1737,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;
 
@@ -1653,8 +1865,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
       {
@@ -1667,7 +1879,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 );
@@ -1707,15 +1919,15 @@ 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 )
+          for ( size_t iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
           {
             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
@@ -1726,7 +1938,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
@@ -1820,7 +2032,7 @@ namespace
             connectivity[ connSize++ ] = baryCenInd;
           }
         }
-        method._nbTetra += nbTet;
+        method._nbSplits += nbTet;
 
       } // loop on volume faces
 
@@ -1830,13 +2042,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);
@@ -1846,16 +2177,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;
     }
@@ -1888,19 +2219,19 @@ 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;
@@ -1910,30 +2241,35 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
   // map face of volume to it's baricenrtic node
   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
   double bc[3];
+  vector<const SMDS_MeshElement* > splitVols;
 
-  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
@@ -1951,7 +2287,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 )
     {
@@ -1979,16 +2316,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
+    splitVols.resize( splitMethod._nbSplits ); // splits of a volume
+    const int* volConn = splitMethod._connectivity;
+    if ( splitMethod._nbCorners == 4 ) // tetra
+      for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners )
+        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
 
@@ -2017,22 +2363,42 @@ 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
         {
-          // among possible triangles create ones discribed by split method
+          // among possible triangles create ones described by split method
           const int* nInd = volTool.GetFaceNodesIndices( iF );
           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
           int iCom = 0; // common node of triangle faces to split into
@@ -2057,6 +2423,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 ))
@@ -2066,20 +2434,20 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
                                                  volNodes[ facet->_n3 ]));
           }
         }
-        for ( int i = 0; i < triangles.size(); ++i )
+        for ( size_t i = 0; i < triangles.size(); ++i )
         {
-          if ( !triangles[i] ) continue;
+          if ( !triangles[ i ]) continue;
           if ( fSubMesh )
-            fSubMesh->AddElement( triangles[i]);
-          newElems.Append( triangles[i] );
+            fSubMesh->AddElement( triangles[ i ]);
+          newElems.Append( triangles[ i ]);
         }
         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 )
     {
@@ -2095,85 +2463,459 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
 }
 
 //=======================================================================
-//function : AddToSameGroups
-//purpose  : add elemToAdd to the groups the elemInGroups belongs to
+//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::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
-                                        const SMDS_MeshElement* elemInGroups,
-                                        SMESHDS_Mesh *          aMesh)
+void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas,
+                                             const gp_Ax1&     theFacetNormal,
+                                             TFacetOfElem &    theFacets)
 {
-  const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
-  if (!groups.empty()) {
-    set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
-    for ( ; grIt != groups.end(); grIt++ ) {
-      SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
-      if ( group && group->Contains( elemInGroups ))
-        group->SMDSGroup().Add( elemToAdd );
-    }
-  }
-}
+  #define THIS_METHOD "SMESH_MeshEditor::GetHexaFacetsToSplit(): "
 
+  // Find a hexa closest to the location of theFacetNormal
 
-//=======================================================================
-//function : RemoveElemFromGroups
-//purpose  : Remove removeelem to the groups the elemInGroups belongs to
-//=======================================================================
-void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
-                                             SMESHDS_Mesh *          aMesh)
-{
-  const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
-  if (!groups.empty())
+  const SMDS_MeshElement* startHex;
   {
-    set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
-    for (; GrIt != groups.end(); GrIt++)
-    {
-      SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
-      if (!grp || grp->IsEmpty()) continue;
-      grp->SMDSGroup().Remove(removeelem);
-    }
+    // 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");
   }
-}
 
-//================================================================================
-/*!
- * \brief Replace elemToRm by elemToAdd in the all groups
- */
-//================================================================================
+  // Select a facet of startHex by theFacetNormal
 
-void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
-                                            const SMDS_MeshElement* elemToAdd,
-                                            SMESHDS_Mesh *          aMesh)
-{
-  const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
-  if (!groups.empty()) {
-    set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
-    for ( ; grIt != groups.end(); grIt++ ) {
-      SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
-      if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
-        group->SMDSGroup().Add( elemToAdd );
+  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");
 
-//================================================================================
-/*!
- * \brief Replace elemToRm by elemToAdd in the all groups
- */
-//================================================================================
+  // Fill theFacets starting from facetID of startHex
 
-void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
-                                            const vector<const SMDS_MeshElement*>& elemToAdd,
-                                            SMESHDS_Mesh *                         aMesh)
-{
-  const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
-  if (!groups.empty())
-  {
-    set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
+  // facets used for searching 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 = ((int) 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 )
+
+  return;
+}
+
+namespace
+{
+  //================================================================================
+  /*!
+   * \brief Selects nodes of several elements according to a given interlace
+   *  \param [in] srcNodes - nodes to select from
+   *  \param [out] tgtNodesVec - array of nodes of several elements to fill in
+   *  \param [in] interlace - indices of nodes for all elements
+   *  \param [in] nbElems - nb of elements
+   *  \param [in] nbNodes - nb of nodes in each element
+   *  \param [in] mesh - the mesh
+   *  \param [out] elemQueue - a list to push elements found by the selected nodes
+   *  \param [in] type - type of elements to look for
+   */
+  //================================================================================
+
+  void selectNodes( const vector< const SMDS_MeshNode* >& srcNodes,
+                    vector< const SMDS_MeshNode* >*       tgtNodesVec,
+                    const int*                            interlace,
+                    const int                             nbElems,
+                    const int                             nbNodes,
+                    SMESHDS_Mesh*                         mesh = 0,
+                    list< const SMDS_MeshElement* >*      elemQueue=0,
+                    SMDSAbs_ElementType                   type=SMDSAbs_All)
+  {
+    for ( int iE = 0; iE < nbElems; ++iE )
+    {
+      vector< const SMDS_MeshNode* >& elemNodes = tgtNodesVec[iE];
+      const int*                         select = & interlace[iE*nbNodes];
+      elemNodes.resize( nbNodes );
+      for ( int iN = 0; iN < nbNodes; ++iN )
+        elemNodes[iN] = srcNodes[ select[ iN ]];
+    }
+    const SMDS_MeshElement* e;
+    if ( elemQueue )
+      for ( int iE = 0; iE < nbElems; ++iE )
+        if (( e = mesh->FindElement( tgtNodesVec[iE], type, /*noMedium=*/false)))
+          elemQueue->push_back( e );
+  }
+}
+
+//=======================================================================
+/*
+ * Split bi-quadratic elements into linear ones without creation of additional nodes
+ *   - bi-quadratic triangle will be split into 3 linear quadrangles;
+ *   - bi-quadratic quadrangle will be split into 4 linear quadrangles;
+ *   - tri-quadratic hexahedron will be split into 8 linear hexahedra;
+ *   Quadratic elements of lower dimension  adjacent to the split bi-quadratic element
+ *   will be split in order to keep the mesh conformal.
+ *  \param elems - elements to split
+ */
+//=======================================================================
+
+void SMESH_MeshEditor::SplitBiQuadraticIntoLinear(TIDSortedElemSet& theElems)
+{
+  vector< const SMDS_MeshNode* > elemNodes(27), subNodes[12], splitNodes[8];
+  vector<const SMDS_MeshElement* > splitElems;
+  list< const SMDS_MeshElement* > elemQueue;
+  list< const SMDS_MeshElement* >::iterator elemIt;
+
+  SMESHDS_Mesh * mesh = GetMeshDS();
+  ElemFeatures *elemType, hexaType(SMDSAbs_Volume), quadType(SMDSAbs_Face), segType(SMDSAbs_Edge);
+  int nbElems, nbNodes;
+
+  TIDSortedElemSet::iterator elemSetIt = theElems.begin();
+  for ( ; elemSetIt != theElems.end(); ++elemSetIt )
+  {
+    elemQueue.clear();
+    elemQueue.push_back( *elemSetIt );
+    for ( elemIt = elemQueue.begin(); elemIt != elemQueue.end(); ++elemIt )
+    {
+      const SMDS_MeshElement* elem = *elemIt;
+      switch( elem->GetEntityType() )
+      {
+      case SMDSEntity_TriQuad_Hexa: // HEX27
+      {
+        elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
+        nbElems  = nbNodes = 8;
+        elemType = & hexaType;
+
+        // get nodes for new elements
+        static int vInd[8][8] = {{ 0,8,20,11,   16,21,26,24 },
+                                 { 1,9,20,8,    17,22,26,21 },
+                                 { 2,10,20,9,   18,23,26,22 },
+                                 { 3,11,20,10,  19,24,26,23 },
+                                 { 16,21,26,24, 4,12,25,15  },
+                                 { 17,22,26,21, 5,13,25,12  },
+                                 { 18,23,26,22, 6,14,25,13  },
+                                 { 19,24,26,23, 7,15,25,14  }};
+        selectNodes( elemNodes, & splitNodes[0], &vInd[0][0], nbElems, nbNodes );
+
+        // add boundary faces to elemQueue
+        static int fInd[6][9] = {{ 0,1,2,3, 8,9,10,11,   20 },
+                                 { 4,5,6,7, 12,13,14,15, 25 },
+                                 { 0,1,5,4, 8,17,12,16,  21 },
+                                 { 1,2,6,5, 9,18,13,17,  22 },
+                                 { 2,3,7,6, 10,19,14,18, 23 },
+                                 { 3,0,4,7, 11,16,15,19, 24 }};
+        selectNodes( elemNodes, & subNodes[0], &fInd[0][0], 6,9, mesh, &elemQueue, SMDSAbs_Face );
+
+        // add boundary segments to elemQueue
+        static int eInd[12][3] = {{ 0,1,8 }, { 1,2,9 }, { 2,3,10 }, { 3,0,11 },
+                                  { 4,5,12}, { 5,6,13}, { 6,7,14 }, { 7,4,15 },
+                                  { 0,4,16}, { 1,5,17}, { 2,6,18 }, { 3,7,19 }};
+        selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 12,3, mesh, &elemQueue, SMDSAbs_Edge );
+        break;
+      }
+      case SMDSEntity_BiQuad_Triangle: // TRIA7
+      {
+        elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
+        nbElems = 3;
+        nbNodes = 4;
+        elemType = & quadType;
+
+        // get nodes for new elements
+        static int fInd[3][4] = {{ 0,3,6,5 }, { 1,4,6,3 }, { 2,5,6,4 }};
+        selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes );
+
+        // add boundary segments to elemQueue
+        static int eInd[3][3] = {{ 0,1,3 }, { 1,2,4 }, { 2,0,5 }};
+        selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 3,3, mesh, &elemQueue, SMDSAbs_Edge );
+        break;
+      }
+      case SMDSEntity_BiQuad_Quadrangle: // QUAD9
+      {
+        elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
+        nbElems = 4;
+        nbNodes = 4;
+        elemType = & quadType;
+
+        // get nodes for new elements
+        static int fInd[4][4] = {{ 0,4,8,7 }, { 1,5,8,4 }, { 2,6,8,5 }, { 3,7,8,6 }};
+        selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes );
+
+        // add boundary segments to elemQueue
+        static int eInd[4][3] = {{ 0,1,4 }, { 1,2,5 }, { 2,3,6 }, { 3,0,7 }};
+        selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 4,3, mesh, &elemQueue, SMDSAbs_Edge );
+        break;
+      }
+      case SMDSEntity_Quad_Edge:
+      {
+        if ( elemIt == elemQueue.begin() )
+          continue; // an elem is in theElems
+        elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
+        nbElems = 2;
+        nbNodes = 2;
+        elemType = & segType;
+
+        // get nodes for new elements
+        static int eInd[2][2] = {{ 0,2 }, { 2,1 }};
+        selectNodes( elemNodes, & splitNodes[0], &eInd[0][0], nbElems, nbNodes );
+        break;
+      }
+      default: continue;
+      } // switch( elem->GetEntityType() )
+
+      // Create new elements
+
+      SMESHDS_SubMesh* subMesh = mesh->MeshElements( elem->getshapeId() );
+
+      splitElems.clear();
+
+      //elemType->SetID( elem->GetID() ); // create an elem with the same ID as a removed one
+      mesh->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false );
+      //splitElems.push_back( AddElement( splitNodes[ 0 ], *elemType ));
+      //elemType->SetID( -1 );
+
+      for ( int iE = 0; iE < nbElems; ++iE )
+        splitElems.push_back( AddElement( splitNodes[ iE ], *elemType ));
+
+
+      ReplaceElemInGroups( elem, splitElems, mesh );
+
+      if ( subMesh )
+        for ( size_t i = 0; i < splitElems.size(); ++i )
+          subMesh->AddElement( splitElems[i] );
+    }
+  }
+}
+
+//=======================================================================
+//function : AddToSameGroups
+//purpose  : add elemToAdd to the groups the elemInGroups belongs to
+//=======================================================================
+
+void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
+                                        const SMDS_MeshElement* elemInGroups,
+                                        SMESHDS_Mesh *          aMesh)
+{
+  const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
+  if (!groups.empty()) {
+    set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
+    for ( ; grIt != groups.end(); grIt++ ) {
+      SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
+      if ( group && group->Contains( elemInGroups ))
+        group->SMDSGroup().Add( elemToAdd );
+    }
+  }
+}
+
+
+//=======================================================================
+//function : RemoveElemFromGroups
+//purpose  : Remove removeelem to the groups the elemInGroups belongs to
+//=======================================================================
+void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
+                                             SMESHDS_Mesh *          aMesh)
+{
+  const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
+  if (!groups.empty())
+  {
+    set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
+    for (; GrIt != groups.end(); GrIt++)
+    {
+      SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
+      if (!grp || grp->IsEmpty()) continue;
+      grp->SMDSGroup().Remove(removeelem);
+    }
+  }
+}
+
+//================================================================================
+/*!
+ * \brief Replace elemToRm by elemToAdd in the all groups
+ */
+//================================================================================
+
+void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
+                                            const SMDS_MeshElement* elemToAdd,
+                                            SMESHDS_Mesh *          aMesh)
+{
+  const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
+  if (!groups.empty()) {
+    set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
+    for ( ; grIt != groups.end(); grIt++ ) {
+      SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
+      if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
+        group->SMDSGroup().Add( elemToAdd );
+    }
+  }
+}
+
+//================================================================================
+/*!
+ * \brief Replace elemToRm by elemToAdd in the all groups
+ */
+//================================================================================
+
+void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
+                                            const vector<const SMDS_MeshElement*>& elemToAdd,
+                                            SMESHDS_Mesh *                         aMesh)
+{
+  const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
+  if (!groups.empty())
+  {
+    set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
     for ( ; grIt != groups.end(); grIt++ ) {
       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
       if ( group && group->SMDSGroup().Remove( elemToRm ) )
-        for ( int i = 0; i < elemToAdd.size(); ++i )
+        for ( size_t i = 0; i < elemToAdd.size(); ++i )
           group->SMDSGroup().Add( elemToAdd[ i ] );
     }
   }
@@ -2191,22 +2933,19 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
-  MESSAGE( "::QuadToTri()" );
-
   SMESHDS_Mesh * aMesh = GetMeshDS();
 
   Handle(Geom_Surface) surface;
   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 )
+    if ( !elem || elem->GetGeomType() != SMDSGeom_QUADRANGLE )
       continue;
-    bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
-    if(!isquad) continue;
 
-    if(elem->NbNodes()==4) {
+    if ( elem->NbNodes() == 4 ) {
       // retrieve element nodes
       const SMDS_MeshNode* aNodes [4];
       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
@@ -2229,20 +2968,19 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
       myLastCreatedElems.Append(newElem2);
       // put a new triangle on the same shape and add to the same groups
       if ( aShapeId )
-        {
-          aMesh->SetMeshElementOnShape( newElem1, aShapeId );
-          aMesh->SetMeshElementOnShape( newElem2, aShapeId );
-        }
+      {
+        aMesh->SetMeshElementOnShape( newElem1, aShapeId );
+        aMesh->SetMeshElementOnShape( newElem2, aShapeId );
+      }
       AddToSameGroups( newElem1, elem, aMesh );
       AddToSameGroups( newElem2, elem, aMesh );
-      //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
       aMesh->RemoveElement( elem );
     }
 
     // Quadratic quadrangle
 
-    if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
-
+    else if ( elem->NbNodes() >= 8 )
+    {
       // get surface elem is on
       int aShapeId = FindShape( elem );
       if ( aShapeId != helper.GetSubShapeID() ) {
@@ -2258,61 +2996,43 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
         }
       }
 
-      const SMDS_MeshNode* aNodes [8];
-      const SMDS_MeshNode* inFaceNode = 0;
+      const SMDS_MeshNode* aNodes [9]; aNodes[8] = 0;
       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-      int i = 0;
-      while ( itN->more() ) {
-        aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
-        if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
-             aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
-        {
-          inFaceNode = aNodes[ i-1 ];
-        }
-      }
+      for ( int i = 0; itN->more(); ++i )
+        aNodes[ i ] = static_cast<const SMDS_MeshNode*>( itN->next() );
 
-      // find middle point for (0,1,2,3)
-      // and create a node in this point;
-      gp_XYZ p( 0,0,0 );
-      if ( surface.IsNull() ) {
-        for(i=0; i<4; i++)
-          p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
-        p /= 4;
-      }
-      else {
-        TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
-        gp_XY uv( 0,0 );
-        for(i=0; i<4; i++)
-          uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
-        uv /= 4.;
-        p = surface->Value( uv.X(), uv.Y() ).XYZ();
+      const SMDS_MeshNode* centrNode = aNodes[8];
+      if ( centrNode == 0 )
+      {
+        centrNode = helper.GetCentralNode( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
+                                           aNodes[4], aNodes[5], aNodes[6], aNodes[7],
+                                           surface.IsNull() );
+        myLastCreatedNodes.Append(centrNode);
       }
-      const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
-      myLastCreatedNodes.Append(newN);
 
       // create a new element
       const SMDS_MeshElement* newElem1 = 0;
       const SMDS_MeshElement* newElem2 = 0;
       if ( the13Diag ) {
         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
-                                  aNodes[6], aNodes[7], newN );
+                                  aNodes[6], aNodes[7], centrNode );
         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
-                                  newN,      aNodes[4], aNodes[5] );
+                                  centrNode, aNodes[4], aNodes[5] );
       }
       else {
         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
-                                  aNodes[7], aNodes[4], newN );
+                                  aNodes[7], aNodes[4], centrNode );
         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
-                                  newN,      aNodes[5], aNodes[6] );
+                                  centrNode, aNodes[5], aNodes[6] );
       }
       myLastCreatedElems.Append(newElem1);
       myLastCreatedElems.Append(newElem2);
       // put a new triangle on the same shape and add to the same groups
       if ( aShapeId )
-        {
-          aMesh->SetMeshElementOnShape( newElem1, aShapeId );
-          aMesh->SetMeshElementOnShape( newElem2, aShapeId );
-        }
+      {
+        aMesh->SetMeshElementOnShape( newElem1, aShapeId );
+        aMesh->SetMeshElementOnShape( newElem2, aShapeId );
+      }
       AddToSameGroups( newElem1, elem, aMesh );
       AddToSameGroups( newElem2, elem, aMesh );
       aMesh->RemoveElement( elem );
@@ -2433,8 +3153,6 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
-  MESSAGE( "::TriToQuad()" );
-
   if ( !theCrit.get() )
     return false;
 
@@ -2539,7 +3257,7 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
       if ( startElem ) {
         // Get candidates to be fused
         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
-        const SMESH_TLink *link12, *link13;
+        const SMESH_TLink *link12 = 0, *link13 = 0;
         startElem = 0;
         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
@@ -3188,13 +3906,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 );
@@ -3223,8 +3936,6 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
-  MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
-
   if ( theTgtAspectRatio < 1.0 )
     theTgtAspectRatio = 1.0;
 
@@ -3263,28 +3974,33 @@ 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;
     TopoDS_Face face;
-    double fToler2 = 0, f,l;
+    double fToler2 = 0;
     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 );
       fToler2 = BRep_Tool::Tolerance( face );
       fToler2 *= fToler2 * 10.;
       isUPeriodic = surface->IsUPeriodic();
-      if ( isUPeriodic )
-        surface->UPeriod();
+      // if ( isUPeriodic )
+      //   surface->UPeriod();
       isVPeriodic = surface->IsVPeriodic();
-      if ( isVPeriodic )
-        surface->VPeriod();
+      // if ( isVPeriodic )
+      //   surface->VPeriod();
       surface->Bounds( u1, u2, v1, v2 );
+      helper.SetSubShape( face );
     }
     // ---------------------------------------------------------
     // for elements on a face, find movable and fixed nodes and
@@ -3306,7 +4022,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
 
@@ -3340,9 +4057,9 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
         {
           // check if all faces around the node are on faceSubMesh
           // because a node on edge may be bound to face
-          SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
           bool all = true;
           if ( faceSubMesh ) {
+            SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
             while ( eIt->more() && all ) {
               const SMDS_MeshElement* e = eIt->next();
               all = faceSubMesh->Contains( e );
@@ -3362,12 +4079,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
@@ -3393,41 +4113,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);
           }
@@ -3437,9 +4137,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;
           }
         }
@@ -3507,9 +4207,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();
@@ -3559,12 +4258,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++;
               }
@@ -3641,18 +4342,18 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
         }
       }
       if ( maxRatio <= theTgtAspectRatio ) {
-        MESSAGE("-- quality achived --");
+        //MESSAGE("-- quality achieved --");
         break;
       }
       if (it+1 == theNbIterations) {
-        MESSAGE("-- Iteration limit exceeded --");
+        //MESSAGE("-- Iteration limit exceeded --");
       }
     } // smoothing iterations
 
-    MESSAGE(" Face id: " << *fId <<
-            " Nb iterstions: " << it <<
-            " Displacement: " << maxDisplacement <<
-            " Aspect Ratio " << maxRatio);
+    // MESSAGE(" Face id: " << *fId <<
+    //         " Nb iterstions: " << it <<
+    //         " Displacement: " << maxDisplacement <<
+    //         " Aspect Ratio " << maxRatio);
 
     // ---------------------------------------
     // new nodes positions are computed,
@@ -3673,8 +4374,6 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
     // move medium nodes of quadratic elements
     if ( isQuadratic )
     {
-      SMESH_MesherHelper helper( *GetMesh() );
-      helper.SetSubShape( face );
       vector<const SMDS_MeshNode*> nodes;
       bool checkUV;
       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
@@ -3711,26 +4410,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 );
+
+    return faceNorm * extrDir < 0.0;
+  }
 
-  SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
-  SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
-  gp_XYZ extrDir( pN - pP ), faceNorm;
-  SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false );
+  //================================================================================
+  /*!
+   * \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] );
+    }
+  }
 }
 
 //=======================================================================
@@ -3747,10 +4469,9 @@ static bool isReverse(const SMDS_MeshElement*             face,
 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
                                     list<const SMDS_MeshElement*>&        newElems,
-                                    const int                             nbSteps,
+                                    const size_t                          nbSteps,
                                     SMESH_SequenceOfElemPtr&              srcElements)
 {
-  //MESSAGE("sweepElement " << nbSteps);
   SMESHDS_Mesh* aMesh = GetMeshDS();
 
   const int           nbNodes = elem->NbNodes();
@@ -3810,7 +4531,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 );
@@ -3830,6 +4551,34 @@ 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] );
+#if defined(__APPLE__)
+        std::swap( isSingleNode[0], isSingleNode[1] );
+#else
+        isSingleNode.swap( isSingleNode[0], isSingleNode[1] );
+#endif
+        if ( nbSame > 0 )
+          sames[0] = 1 - sames[0];
+        iNotSameNode = 1 - iNotSameNode;
+      }
+    }
+  }
 
   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
   if ( nbSame > 0 ) {
@@ -3839,8 +4588,19 @@ 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++ )
+  for ( size_t iStep = 0; iStep < nbSteps; iStep++ )
   {
     // get next nodes
     for ( iNode = 0; iNode < nbNodes; iNode++ )
@@ -3935,11 +4695,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 )
@@ -3984,7 +4744,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
         break;
       }
       case SMDSEntity_Quad_Triangle:  // sweep (Bi)Quadratic TRIANGLE --->
-      case SMDSEntity_BiQuad_Triangle: /* ??? */ { 
+      case SMDSEntity_BiQuad_Triangle: /* ??? */ {
         if ( nbDouble+nbSame != 3 ) break;
         if(nbSame==0) {
           // --->  pentahedron with 15 nodes
@@ -4036,7 +4796,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
         else if(nbSame==1) {
           // ---> 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" );
+          //INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
           return;
         }
         else if( nbSame == 2 ) {
@@ -4105,14 +4865,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 );
@@ -4137,21 +4897,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 )
@@ -4160,7 +4929,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 );
@@ -4172,7 +4942,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
     for ( iNode = 0; iNode < nbNodes; iNode++ )
       prevNod[ iNode ] = nextNod[ iNode ];
 
-  } // for steps
+  } // loop on steps
 }
 
 //=======================================================================
@@ -4188,7 +4958,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,
@@ -4211,16 +4981,20 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
     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();
-      if ( type == SMDSAbs_Volume || type < highType ) continue;
+      const SMDS_MeshElement* e = eIt->next();
+      SMDSAbs_ElementType  type = e->GetType();
+      if ( type == SMDSAbs_Volume ||
+           type < highType ||
+           !elemSet.count(e))
+        continue;
       if ( type > highType ) {
         nbInitElems = 0;
-        highType = type;
+        highType    = type;
       }
-      nbInitElems += elemSet.count(el);
+      el = e;
+      ++nbInitElems;
     }
-    if ( nbInitElems < 2 ) {
+    if ( nbInitElems == 1 ) {
       bool NotCreateEdge = el && el->IsMediumNode(node);
       if(!NotCreateEdge) {
         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
@@ -4233,7 +5007,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++ )
   {
@@ -4336,7 +5112,7 @@ 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;
 
@@ -4370,11 +5146,12 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
             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]));
@@ -4390,10 +5167,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;
@@ -4520,7 +5298,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() ));
               }
             }
 
@@ -4547,36 +5325,20 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
       aFaceLastNodes.erase( vecNewNodes.back()->second.back() );
       iF = lastVol.GetFaceIndex( aFaceLastNodes );
     }
-    if ( iF >= 0 ) {
+    if ( iF >= 0 )
+    {
       lastVol.SetExternalNormal();
       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
-      int nbn = lastVol.NbFaceNodes( iF );
-      // we do not use this->AddElement() because nodes are interlaced
+      const               int nbn = lastVol.NbFaceNodes( iF );
       vector<const SMDS_MeshNode*> nodeVec( nodes, nodes+nbn );
       if ( !hasFreeLinks ||
            !aMesh->FindElement( nodeVec, SMDSAbs_Face, /*noMedium=*/false) )
       {
-        if ( nbn == 3 )
-          myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2] ));
-
-        else if ( nbn == 4 )
-          myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2], nodes[3]));
-
-        else if ( nbn == 6 && isQuadratic )
-          myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4],
-                                                    nodes[1], nodes[3], nodes[5]));
-        else if ( nbn == 7 && isQuadratic )
-          myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4],
-                                                    nodes[1], nodes[3], nodes[5], nodes[6]));
-        else if ( nbn == 8 && isQuadratic )
-          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 )
-          myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], nodes[6],
-                                                    nodes[1], nodes[3], nodes[5], nodes[7],
-                                                    nodes[8]));
-        else
-          myLastCreatedElems.Append(aMesh->AddPolygonalFace( nodeVec ));
+        const vector<int>& interlace =
+          SMDS_MeshCell::interlacedSmdsOrder( elem->GetEntityType(), nbn );
+        SMDS_MeshCell::applyInterlaceRev( interlace, nodeVec );
+
+        AddElement( nodeVec, anyFace.Init( elem ));
 
         while ( srcElements.Length() < myLastCreatedElems.Length() )
           srcElements.Append( elem );
@@ -4591,7 +5353,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,
@@ -4605,7 +5367,6 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
   // source elements for each generated one
   SMESH_SequenceOfElemPtr srcElems, srcNodes;
 
-  MESSAGE( "RotationSweep()");
   gp_Trsf aTrsf;
   aTrsf.SetRotation( theAxis, theAngle );
   gp_Trsf aTrsf2;
@@ -4618,89 +5379,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 )
@@ -4709,50 +5475,423 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
   return newGroupIDs;
 }
 
+//=======================================================================
+//function : ExtrusParam
+//purpose  : standard construction
+//=======================================================================
+
+SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Vec&            theStep,
+                                            const int                theNbSteps,
+                                            const std::list<double>& theScales,
+                                            const gp_XYZ*            theBasePoint,
+                                            const int                theFlags,
+                                            const double             theTolerance):
+  myDir( theStep ),
+  myBaseP( Precision::Infinite(), 0, 0 ),
+  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 );
+
+  int nbScales = theScales.size();
+  if ( nbScales > 0 )
+  {
+    if ( IsLinearVariation() && nbScales < theNbSteps )
+    {
+      myScales.reserve( theNbSteps );
+      std::list<double>::const_iterator scale = theScales.begin();
+      double prevScale = 1.0;
+      for ( int iSc = 1; scale != theScales.end(); ++scale, ++iSc )
+      {
+        int      iStep = int( iSc / double( nbScales ) * theNbSteps + 0.5 );
+        int    stDelta = Max( 1, iStep - myScales.size());
+        double scDelta = ( *scale - prevScale ) / stDelta;
+        for ( int iStep = 0; iStep < stDelta; ++iStep )
+        {
+          myScales.push_back( prevScale + scDelta );
+          prevScale = myScales.back();
+        }
+        prevScale = *scale;
+      }
+    }
+    else
+    {
+      myScales.assign( theScales.begin(), theScales.end() );
+    }
+  }
+  if ( theBasePoint )
+  {
+    myBaseP = *theBasePoint;
+  }
+
+  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;
+  }
+}
+
 //=======================================================================
-const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
-                                                  const double y,
-                                                  const double z,
-                                                  const double tolnode,
-                                                  SMESH_SequenceOfNode& aNodes)
+//function : ExtrusParam::SetElementsToUse
+//purpose  : stores elements to use for extrusion by normal, depending on
+//           state of EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY flag;
+//           define myBaseP for scaling
+//=======================================================================
+
+void SMESH_MeshEditor::ExtrusParam::SetElementsToUse( const TIDSortedElemSet& elems,
+                                                      const TIDSortedElemSet& nodes )
 {
-  // myLastCreatedElems.Clear();
-  // myLastCreatedNodes.Clear();
+  myElemsToUse = ToUseInpElemsOnly() ? & elems : 0;
 
-  gp_Pnt P1(x,y,z);
-  SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
+  if ( Precision::IsInfinite( myBaseP.X() )) // myBaseP not defined
+  {
+    myBaseP.SetCoord( 0.,0.,0. );
+    TIDSortedElemSet newNodes;
 
-  // 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);
+    const TIDSortedElemSet* elemSets[] = { &elems, &nodes };
+    for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
+    {
+      const TIDSortedElemSet& elements = *( elemSets[ is2ndSet ]);
+      TIDSortedElemSet::const_iterator itElem = elements.begin();
+      for ( ; itElem != elements.end(); itElem++ )
+      {
+        const SMDS_MeshElement* elem = *itElem;
+        SMDS_ElemIteratorPtr     itN = elem->nodesIterator();
+        while ( itN->more() ) {
+          const SMDS_MeshElement* node = itN->next();
+          if ( newNodes.insert( node ).second )
+            myBaseP += SMESH_TNodeXYZ( node );
+        }
+      }
     }
+    myBaseP /= newNodes.size();
   }
-  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;
+}
+
+//=======================================================================
+//function : ExtrusParam::beginStepIter
+//purpose  : prepare iteration on steps
+//=======================================================================
+
+void SMESH_MeshEditor::ExtrusParam::beginStepIter( bool withMediumNodes )
+{
+  myWithMediumNodes = withMediumNodes;
+  myNextStep = 1;
+  myCurSteps.clear();
+}
+//=======================================================================
+//function : ExtrusParam::moreSteps
+//purpose  : are there more steps?
+//=======================================================================
+
+bool SMESH_MeshEditor::ExtrusParam::moreSteps()
+{
+  return myNextStep <= mySteps->Length() || !myCurSteps.empty();
+}
+//=======================================================================
+//function : ExtrusParam::nextStep
+//purpose  : returns the next step
+//=======================================================================
+
+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();
+  }
+  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 );
+  }
+
+  if ( !myScales.empty() )
+  {
+    if ( makeMediumNodes && myMediumScales.empty() )
+    {
+      myMediumScales.resize( myScales.size() );
+      double prevFactor = 1.;
+      for ( size_t i = 0; i < myScales.size(); ++i )
+      {
+        myMediumScales[i] = 0.5 * ( prevFactor + myScales[i] );
+        prevFactor = myScales[i];
+      }
+    }
+    typedef std::vector<double>::iterator ScaleIt;
+    ScaleIt scales[] = { myScales.begin(), myMediumScales.begin() };
+
+    size_t iSc = 0, nbScales = myScales.size() + myMediumScales.size();
+
+    gp_XYZ center = myBaseP;
+    std::list<const SMDS_MeshNode*>::iterator nIt = newNodes.begin();
+    size_t iN  = 0;
+    for ( beginStepIter( makeMediumNodes ); moreSteps() && ( iN < nbScales ); ++nIt, ++iN )
+    {
+      center += myDir.XYZ() * nextStep();
+
+      iSc += int( makeMediumNodes );
+      ScaleIt& scale = scales[ iSc % 2 ];
+      
+      gp_XYZ xyz = SMESH_TNodeXYZ( *nIt );
+      xyz = ( *scale * ( xyz - center )) + center;
+      mesh->MoveNode( *nIt, xyz.X(), xyz.Y(), xyz.Z() );
+
+      ++scale;
+    }
+  }
+  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
@@ -4760,24 +5899,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, std::list<double>(), 0, theFlags, theTolerance );
+  return ExtrusionSweep( theElems, aParams, newElemsMap );
 }
 
 
@@ -4787,12 +5917,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();
@@ -4800,105 +5927,87 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
   // source elements for each generated one
   SMESH_SequenceOfElemPtr srcElems, srcNodes;
 
-  SMESHDS_Mesh* aMesh = GetMeshDS();
-
-  int nbsteps = theParams.mySteps->Length();
+  setElemsFirst( theElemSets );
+  const int nbSteps = theParams.NbSteps();
+  theParams.SetElementsToUse( theElemSets[0], theElemSets[1] );
 
-  TNodeOfNodeListMap mapNewNodes;
-  //TNodeOfNodeVecMap mapNewNodes;
+  TNodeOfNodeListMap   mapNewNodes;
   TElemOfVecOfNnlmiMap mapElemNewNodes;
-  //TElemOfVecOfMapNodesMap mapElemNewNodes;
 
   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
                                      myMesh->NbFaces(ORDER_QUADRATIC) +
                                      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;
@@ -4909,7 +6018,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,
@@ -4919,7 +6028,6 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
                                        const gp_Pnt&        theRefPoint,
                                        const bool           theMakeGroups)
 {
-  MESSAGE("ExtrusionAlongTrack");
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
@@ -4938,7 +6046,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;
@@ -4947,6 +6055,10 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
   ASSERT( theTrack );
 
   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
+  if ( !pSubMeshDS )
+    return ExtrusionAlongTrack( theElements, theTrack->GetFather(), theN1,
+                                theHasAngles, theAngles, theLinearVariation,
+                                theHasRefPoint, theRefPoint, theMakeGroups );
 
   aItE = pSubMeshDS->GetElements();
   while ( aItE->more() ) {
@@ -4964,7 +6076,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();
@@ -4983,7 +6095,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
       aPrms.push_back( aT );
     }
     //Extrusion_Error err =
-    MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
+    makeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
   } else if( aS.ShapeType() == TopAbs_WIRE ) {
     list< SMESH_subMesh* > LSM;
     TopTools_SequenceOfShape Edges;
@@ -5028,7 +6140,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
         }
         list<SMESH_MeshEditor_PathPoint> LPP;
         //Extrusion_Error err =
-        MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
+        makeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
         LLPPs.push_back(LPP);
         UsedNums.Add(k);
         // update startN for search following egde
@@ -5071,7 +6183,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
     return EXTR_BAD_PATH_SHAPE;
   }
 
-  return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
+  return makeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
                           theHasRefPoint, theRefPoint, theMakeGroups);
 }
 
@@ -5081,7 +6193,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,
@@ -5109,7 +6221,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;
@@ -5132,7 +6244,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;
@@ -5150,7 +6262,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
     }
 
     conn = nbEdgeConnectivity(theN1);
-    if(conn > 2)
+    if( conn != 1 )
       return EXTR_PATH_NOT_EDGE;
 
     aItE = theN1->GetInverseElementIterator();
@@ -5201,21 +6313,19 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
       return EXTR_PATH_NOT_EDGE;
 
     TopTools_SequenceOfShape Edges;
-    double x1,x2,y1,y2,z1,z2;
     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
     int startNid = theN1->GetID();
-    for(int i = 1; i < aNodesList.size(); i++) {
-      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));
+    for ( size_t i = 1; i < aNodesList.size(); i++ )
+    {
+      gp_Pnt     p1 = SMESH_TNodeXYZ( aNodesList[i-1] );
+      gp_Pnt     p2 = SMESH_TNodeXYZ( aNodesList[i] );
+      TopoDS_Edge e = BRepBuilderAPI_MakeEdge( p1, p2 );
       list<SMESH_MeshEditor_PathPoint> LPP;
       aPrms.clear();
-      MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
+      makeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
       LLPPs.push_back(LPP);
-      if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
-      else startNid = aNodesList[i-1]->GetID();
-
+      if ( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i  ]->GetID();
+      else                                        startNid = aNodesList[i-1]->GetID();
     }
 
     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
@@ -5235,8 +6345,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
       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( 0.5 * ( D1.XYZ() + D2.XYZ() ));
       PP1.SetTangent(Dnew);
       fullList.push_back(PP1);
       itPP++;
@@ -5249,22 +6358,15 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
     fullList.push_back(PP1);
 
   } // Sub-shape for the Pattern must be an Edge or Wire
-  else if( aS.ShapeType() == TopAbs_EDGE ) {
+  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 );
-    const SMDS_MeshNode* aN1 = 0;
-    const SMDS_MeshNode* aN2 = 0;
-    if ( theTrack->GetSubMesh( aV1 ) && theTrack->GetSubMesh( aV1 )->GetSubMeshDS() ) {
-      aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
-      aN1 = aItN->next();
-    }
-    if ( theTrack->GetSubMesh( aV2 ) && theTrack->GetSubMesh( aV2 )->GetSubMeshDS() ) {
-      aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
-      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;
@@ -5278,7 +6380,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
       aPrms.push_back( aT );
     }
     //Extrusion_Error err =
-    MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
+    makeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
   }
   else if( aS.ShapeType() == TopAbs_WIRE ) {
     list< SMESH_subMesh* > LSM;
@@ -5286,7 +6388,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);
@@ -5312,17 +6414,8 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
         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 = 0;
-          const SMDS_MeshNode* aN2 = 0;
-
-          if ( locTrack->GetFather()->GetSubMesh(aV1) && locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS() ) {
-            aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
-            aN1 = aItN->next();
-          }
-          if ( locTrack->GetFather()->GetSubMesh(aV2) && locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS() ) {
-            aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
-            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
           aN1isOK = ( aN1 && aN1 == theN1 );
           aN2isOK = ( aN2 && aN2 == theN1 );
@@ -5346,7 +6439,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
         }
         list<SMESH_MeshEditor_PathPoint> LPP;
         //Extrusion_Error err =
-        MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
+        makeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
         LLPPs.push_back(LPP);
         UsedNums.Add(k);
         // update startN for search following egde
@@ -5356,27 +6449,21 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
       }
     }
     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( ( D1.XYZ() + D2.XYZ() ) / 2 );
+      gp_Dir Dnew( D1.XYZ() + D2.XYZ() );
       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();
     }
@@ -5388,19 +6475,19 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
     return EXTR_BAD_PATH_SHAPE;
   }
 
-  return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
+  return makeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
                           theHasRefPoint, theRefPoint, theMakeGroups);
 }
 
 
 //=======================================================================
-//function : MakeEdgePathPoints
-//purpose  : auxilary for ExtrusionAlongTrack
+//function : makeEdgePathPoints
+//purpose  : auxiliary 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;
@@ -5438,7 +6525,7 @@ SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
     aL2 = aVec.SquareMagnitude();
     if ( aL2 < aTolVec2 )
       return EXTR_CANT_GET_TANGENT;
-    gp_Dir aTgt( aVec );
+    gp_Dir aTgt( FirstIsStart ? aVec : -aVec );
     aPP.SetPnt( aP3D );
     aPP.SetTangent( aTgt );
     aPP.SetParameter( aT );
@@ -5449,207 +6536,175 @@ SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
 
 
 //=======================================================================
-//function : MakeExtrElements
-//purpose  : auxilary for ExtrusionAlongTrack
+//function : makeExtrElements
+//purpose  : auxiliary 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 ) {
-    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;
-    }
-  }
+  if( theHasAngles && !theAngles.empty() && theLinearVariation )
+    linearAngleVariation(aNbTP-1, theAngles);
+
   // 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;
-
-      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();
+  if ( !theHasRefPoint )
+  {
+    gp_XYZ aGC( 0.,0.,0. );
+    TIDSortedElemSet newNodes;
 
-        if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
-          list<const SMDS_MeshNode*> aLNx;
-          mapNewNodes[node] = aLNx;
-          //
-          gp_XYZ aXYZ( aX, aY, aZ );
-          aGC += aXYZ;
-          ++aNb;
+    for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
+    {
+      TIDSortedElemSet& theElements = theElemSets[ is2ndSet ];
+      itElem = theElements.begin();
+      for ( ; itElem != theElements.end(); itElem++ )
+      {
+        const SMDS_MeshElement* elem = *itElem;
+        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();
+  list<const SMDS_MeshNode*> emptyList;
 
-  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;
+  setElemsFirst( theElemSets );
+  for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
+  {
+    TIDSortedElemSet& theElements = theElemSets[ is2ndSet ];
+    for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ )
+    {
+      const SMDS_MeshElement* elem = *itElem;
 
-    vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
-    newNodesItVec.reserve( elem->NbNodes() );
+      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;
+      // 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 = cast2Node( itN->next() );
+        TNodeOfNodeListMap::iterator nIt = mapNewNodes.insert( make_pair( node, emptyList )).first;
         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
+        if ( listNewNodes.empty() )
+        {
+          // 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();
+
+          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 );
 
-        // 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 );
-
-          // 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 );
-          }
+              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
+            if ( elem->IsQuadratic() && !elem->IsMediumNode(node) )
+            {
+              // create additional node
+              gp_XYZ midP = 0.5 * ( aPN1.XYZ() + aPN0.XYZ() );
+              const SMDS_MeshNode* newNode = aMesh->AddNode( midP.X(), midP.Y(), midP.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) ) {
+        else if( elem->IsQuadratic() && !elem->IsMediumNode(node) )
+        {
+          // if current elem is quadratic and current node is not medium
+          // we have to check - may be it is needed to insert additional nodes
           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
-          if(listNewNodes.size()==aNbTP-1) {
+          if ((int) 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();
@@ -5672,17 +6727,16 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
             }
           }
         }
+
+        newNodesItVec.push_back( nIt );
       }
 
-      newNodesItVec.push_back( nIt );
+      // make new elements
+      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");
@@ -5692,25 +6746,24 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
 
 
 //=======================================================================
-//function : LinearAngleVariation
-//purpose  : auxilary for ExtrusionAlongTrack
+//function : linearAngleVariation
+//purpose  : spread values over nbSteps
 //=======================================================================
-void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
+
+void SMESH_MeshEditor::linearAngleVariation(const int     nbSteps,
                                             list<double>& Angles)
 {
   int nbAngles = Angles.size();
-  if( nbSteps > nbAngles ) {
+  if( nbSteps > nbAngles && nbAngles > 0 )
+  {
     vector<double> theAngles(nbAngles);
-    list<double>::iterator it = Angles.begin();
-    int i = -1;
-    for(; it!=Angles.end(); it++) {
-      i++;
-      theAngles[i] = (*it);
-    }
+    theAngles.assign( Angles.begin(), Angles.end() );
+
     list<double> res;
     double rAn2St = double( nbAngles ) / double( nbSteps );
     double angPrev = 0, angle;
-    for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
+    for ( int iSt = 0; iSt < nbSteps; ++iSt )
+    {
       double angCur = rAn2St * ( iSt+1 );
       double angCurFloor  = floor( angCur );
       double angPrevFloor = floor( angPrev );
@@ -5732,10 +6785,7 @@ void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
       res.push_back(angle);
       angPrev = angCur;
     }
-    Angles.clear();
-    it = res.begin();
-    for(; it!=res.end(); it++)
-      Angles.push_back( *it );
+    Angles.swap( res );
   }
 }
 
@@ -5766,45 +6816,39 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
   string groupPostfix;
   switch ( theTrsf.Form() ) {
   case gp_PntMirror:
-    MESSAGE("gp_PntMirror");
     needReverse = true;
     groupPostfix = "mirrored";
     break;
   case gp_Ax1Mirror:
-    MESSAGE("gp_Ax1Mirror");
     groupPostfix = "mirrored";
     break;
   case gp_Ax2Mirror:
-    MESSAGE("gp_Ax2Mirror");
     needReverse = true;
     groupPostfix = "mirrored";
     break;
   case gp_Rotation:
-    MESSAGE("gp_Rotation");
     groupPostfix = "rotated";
     break;
   case gp_Translation:
-    MESSAGE("gp_Translation");
     groupPostfix = "translated";
     break;
   case gp_Scale:
-    MESSAGE("gp_Scale");
     groupPostfix = "scaled";
     break;
   case gp_CompoundTrsf: // different scale by axis
-    MESSAGE("gp_CompoundTrsf");
     groupPostfix = "scaled";
     break;
   default:
-    MESSAGE("default");
     needReverse = false;
     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;
@@ -5836,196 +6880,116 @@ 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;
     if ( !elem ) continue;
 
     SMDSAbs_GeometryType geomType = elem->GetGeomType();
-    int                  nbNodes  = elem->NbNodes();
+    size_t               nbNodes  = elem->NbNodes();
     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;
+      size_t 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
@@ -6033,32 +6997,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;
 }
@@ -6066,9 +7027,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
  */
 //=======================================================================
 
@@ -6076,14 +7039,17 @@ 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 ones
+  // 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;
@@ -6113,6 +7079,7 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
 
   // Loop on nodes and elements to add them in new groups
 
+  vector< const SMDS_MeshElement* > resultElems;
   for ( int isNodes = 0; isNodes < 2; ++isNodes )
   {
     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
@@ -6135,7 +7102,7 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
         continue;
       }
       // collect all elements made by the iElem-th sourceElem
-      list< const SMDS_MeshElement* > resultElems;
+      resultElems.clear();
       if ( const SMDS_MeshElement* resElem = elems( iElem ))
         if ( resElem != sourceElem )
           resultElems.push_back( resElem );
@@ -6144,25 +7111,23 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
           if ( resElem != sourceElem )
             resultElems.push_back( resElem );
 
-      // there must be a top element
       const SMDS_MeshElement* topElem = 0;
-      if ( isNodes )
+      if ( isNodes ) // there must be a top element
       {
         topElem = resultElems.back();
         resultElems.pop_back();
       }
       else
       {
-        list< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin();
+        vector< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin();
         for ( ; resElemIt != resultElems.rend() ; ++resElemIt )
           if ( (*resElemIt)->GetType() == sourceElem->GetType() )
           {
             topElem = *resElemIt;
-            resultElems.erase( --(resElemIt.base()) ); // erase *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 )
@@ -6172,16 +7137,17 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
         {
           // fill in a new group
           SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup();
-          list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
+          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
@@ -6195,7 +7161,6 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
     SMESHDS_GroupBase* oldGroupDS =   orderedOldNewGroups[i]->get<0>();
     SMESHDS_Group*   newGroups[2] = { orderedOldNewGroups[i]->get<1>(),
                                       orderedOldNewGroups[i]->get<2>() };
-    const int nbNewGroups = !newGroups[0]->IsEmpty() + !newGroups[1]->IsEmpty();
     for ( int is2nd = 0; is2nd < 2; ++is2nd )
     {
       SMESHDS_Group* newGroupDS = newGroups[ is2nd ];
@@ -6209,11 +7174,21 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
         newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
 
         // make a name
-        const bool isTop = ( nbNewGroups == 2 &&
+        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 += "_";
@@ -6243,32 +7218,72 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
 
 //================================================================================
 /*!
- * \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
+  if ( myMesh->NbEdges  ( ORDER_QUADRATIC ) +
+       myMesh->NbFaces  ( ORDER_QUADRATIC ) +
+       myMesh->NbVolumes( ORDER_QUADRATIC ) == 0 )
+    theSeparateCornersAndMedium = false;
+
+  TIDSortedNodeSet& corners = theNodes;
+  TIDSortedNodeSet  medium;
+
+  if ( theNodes.empty() ) // get all nodes in the mesh
+  {
+    TIDSortedNodeSet* nodes[2] = { &corners, &medium };
     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
-    while ( nIt->more() )
-      theNodes.insert( theNodes.end(),nIt->next());
+    if ( theSeparateCornersAndMedium )
+      while ( nIt->more() )
+      {
+        const SMDS_MeshNode* n = nIt->next();
+        TIDSortedNodeSet* & nodeSet = nodes[ SMESH_MesherHelper::IsMedium( n )];
+        nodeSet->insert( nodeSet->end(), n );
+      }
+    else
+      while ( nIt->more() )
+        theNodes.insert( theNodes.end(), nIt->next() );
+  }
+  else if ( theSeparateCornersAndMedium ) // separate corners from medium nodes
+  {
+    TIDSortedNodeSet::iterator nIt = corners.begin();
+    while ( nIt != corners.end() )
+      if ( SMESH_MesherHelper::IsMedium( *nIt ))
+      {
+        medium.insert( medium.end(), *nIt );
+        corners.erase( nIt++ );
+      }
+      else
+      {
+        ++nIt;
+      }
   }
 
-  SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
+  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,
@@ -6276,78 +7291,52 @@ int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *>& faceNod
                                     vector<int>&                         quantities) const
 {
   int nbNodes = faceNodes.size();
-
-  if (nbNodes < 3)
+  while ( faceNodes[ 0 ] == faceNodes[ nbNodes-1 ] && nbNodes > 2 )
+    --nbNodes;
+  if ( nbNodes < 3 )
     return 0;
+  size_t prevNbQuant = quantities.size();
 
-  set<const SMDS_MeshNode*> nodeSet;
-
-  // get simple seq of nodes
-  //const SMDS_MeshNode* simpleNodes[ nbNodes ];
-  vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
-  int iSimple = 0, nbUnique = 0;
-
-  simpleNodes[iSimple++] = faceNodes[0];
-  nbUnique++;
-  for (int iCur = 1; iCur < nbNodes; iCur++) {
-    if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
-      simpleNodes[iSimple++] = faceNodes[iCur];
-      if (nodeSet.insert( faceNodes[iCur] ).second)
-        nbUnique++;
-    }
-  }
-  int nbSimple = iSimple;
-  if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
-    nbSimple--;
-    iSimple--;
-  }
-
-  if (nbUnique < 3)
-    return 0;
+  vector< const SMDS_MeshNode* > simpleNodes; simpleNodes.reserve( nbNodes );
+  map< const SMDS_MeshNode*, int > nodeIndices; // indices within simpleNodes
+  map< const SMDS_MeshNode*, int >::iterator nInd;
 
-  // separate loops
-  int nbNew = 0;
-  bool foundLoop = (nbSimple > nbUnique);
-  while (foundLoop) {
-    foundLoop = false;
-    set<const SMDS_MeshNode*> loopSet;
-    for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
-      const SMDS_MeshNode* n = simpleNodes[iSimple];
-      if (!loopSet.insert( n ).second) {
-        foundLoop = true;
-
-        // separate loop
-        int iC = 0, curLast = iSimple;
-        for (; iC < curLast; iC++) {
-          if (simpleNodes[iC] == n) break;
-        }
-        int loopLen = curLast - iC;
-        if (loopLen > 2) {
-          // create sub-element
-          nbNew++;
-          quantities.push_back(loopLen);
-          for (; iC < curLast; iC++) {
-            poly_nodes.push_back(simpleNodes[iC]);
-          }
-        }
-        // shift the rest nodes (place from the first loop position)
-        for (iC = curLast + 1; iC < nbSimple; iC++) {
-          simpleNodes[iC - loopLen] = simpleNodes[iC];
+  nodeIndices.insert( make_pair( faceNodes[0], 0 ));
+  simpleNodes.push_back( faceNodes[0] );
+  for ( int iCur = 1; iCur < nbNodes; iCur++ )
+  {
+    if ( faceNodes[ iCur ] != simpleNodes.back() )
+    {
+      int index = simpleNodes.size();
+      nInd = nodeIndices.insert( make_pair( faceNodes[ iCur ], index )).first;
+      int prevIndex = nInd->second;
+      if ( prevIndex < index )
+      {
+        // a sub-loop found
+        int loopLen = index - prevIndex;
+        if ( loopLen > 2 )
+        {
+          // store the sub-loop
+          quantities.push_back( loopLen );
+          for ( int i = prevIndex; i < index; i++ )
+            poly_nodes.push_back( simpleNodes[ i ]);
         }
-        nbSimple -= loopLen;
-        iSimple -= loopLen;
+        simpleNodes.resize( prevIndex+1 );
+      }
+      else
+      {
+        simpleNodes.push_back( faceNodes[ iCur ]);
       }
-    } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
-  } // while (foundLoop)
+    }
+  }
 
-  if (iSimple > 2) {
-    nbNew++;
-    quantities.push_back(iSimple);
-    for (int i = 0; i < iSimple; i++)
-      poly_nodes.push_back(simpleNodes[i]);
+  if ( simpleNodes.size() > 2 )
+  {
+    quantities.push_back( simpleNodes.size() );
+    poly_nodes.insert ( poly_nodes.end(), simpleNodes.begin(), simpleNodes.end() );
   }
 
-  return nbNew;
+  return quantities.size() - prevNbQuant;
 }
 
 //=======================================================================
@@ -6356,41 +7345,31 @@ int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *>& faceNod
 //           in all elements.
 //=======================================================================
 
-void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
+void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes,
+                                   const bool           theAvoidMakingHoles)
 {
-  MESSAGE("MergeNodes");
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
-  SMESHDS_Mesh* aMesh = GetMeshDS();
+  SMESHDS_Mesh* mesh = GetMeshDS();
 
   TNodeNodeMap nodeNodeMap; // node to replace - new node
   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
   list< int > rmElemIds, rmNodeIds;
+  vector< ElemFeatures > newElemDefs;
 
   // Fill nodeNodeMap and elems
 
   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
-  for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
+  for ( ; grIt != theGroupsOfNodes.end(); grIt++ )
+  {
     list<const SMDS_MeshNode*>& nodes = *grIt;
     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
     const SMDS_MeshNode* nToKeep = *nIt;
-    //MESSAGE("node to keep " << nToKeep->GetID());
-    for ( ++nIt; nIt != nodes.end(); nIt++ ) {
+    for ( ++nIt; nIt != nodes.end(); nIt++ )
+    {
       const SMDS_MeshNode* nToRemove = *nIt;
-      nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
-      if ( nToRemove != nToKeep ) {
-        //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 );
-      }
-
+      nodeNodeMap.insert( make_pair( nToRemove, nToKeep ));
       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
       while ( invElemIt->more() ) {
         const SMDS_MeshElement* elem = invElemIt->next();
@@ -6398,612 +7377,570 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
       }
     }
   }
+
+  // Apply recursive replacements (BUG 0020185)
+  TNodeNodeMap::iterator nnIt = nodeNodeMap.begin();
+  for ( ; nnIt != nodeNodeMap.end(); ++nnIt )
+  {
+    const SMDS_MeshNode* nToKeep = nnIt->second;
+    TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( nToKeep );
+    while ( nnIt_i != nodeNodeMap.end() && nnIt_i->second != nnIt->second )
+      nToKeep = nnIt_i->second;
+    nnIt->second = nToKeep;
+  }
+
+  if ( theAvoidMakingHoles )
+  {
+    // find elements whose topology changes
+
+    vector<const SMDS_MeshElement*> pbElems;
+    set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
+    for ( ; eIt != elems.end(); ++eIt )
+    {
+      const SMDS_MeshElement* elem = *eIt;
+      SMDS_ElemIteratorPtr     itN = elem->nodesIterator();
+      while ( itN->more() )
+      {
+        const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( itN->next() );
+        TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
+        if ( nnIt != nodeNodeMap.end() && elem->GetNodeIndex( nnIt->second ) >= 0 )
+        {
+          // several nodes of elem stick
+          pbElems.push_back( elem );
+          break;
+        }
+      }
+    }
+    // exclude from merge nodes causing spoiling element
+    for ( size_t iLoop = 0; iLoop < pbElems.size(); ++iLoop ) // avoid infinite cycle
+    {
+      bool nodesExcluded = false;
+      for ( size_t i = 0; i < pbElems.size(); ++i )
+      {
+        size_t prevNbMergeNodes = nodeNodeMap.size();
+        if ( !applyMerge( pbElems[i], newElemDefs, nodeNodeMap, /*noHoles=*/true ) &&
+             prevNbMergeNodes < nodeNodeMap.size() )
+          nodesExcluded = true;
+      }
+      if ( !nodesExcluded )
+        break;
+    }
+  }
+
+  for ( nnIt = nodeNodeMap.begin(); nnIt != nodeNodeMap.end(); ++nnIt )
+  {
+    const SMDS_MeshNode* nToRemove = nnIt->first;
+    const SMDS_MeshNode* nToKeep   = nnIt->second;
+    if ( nToRemove != nToKeep )
+    {
+      rmNodeIds.push_back( nToRemove->GetID() );
+      AddToSameGroups( nToKeep, nToRemove, mesh );
+      // set _alwaysComputed to a sub-mesh of VERTEX to enable further mesh computing
+      // 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 );
+    }
+  }
+
   // Change element nodes or remove an element
 
   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 );
+    SMESHDS_SubMesh*          sm = mesh->MeshElements( elem->getshapeId() );
 
-    set<const SMDS_MeshNode*> nodeSet;
-    vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
-    int iUnique = 0, iCur = 0, nbRepl = 0;
-    vector<int> iRepl( nbNodes );
+    bool keepElem = applyMerge( elem, newElemDefs, nodeNodeMap, /*noHoles=*/false );
+    if ( !keepElem )
+      rmElemIds.push_back( elem->GetID() );
 
-    // get new seq of nodes
-    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-    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
+    for ( size_t i = 0; i < newElemDefs.size(); ++i )
+    {
+      if ( i > 0 || !mesh->ChangeElementNodes( elem,
+                                               & newElemDefs[i].myNodes[0],
+                                               newElemDefs[i].myNodes.size() ))
+      {
+        if ( i == 0 )
         {
-          bool stopRecur = false;
-          set<const SMDS_MeshNode*> nodesRecur;
-          nodesRecur.insert(n);
-          while (!stopRecur) {
-            TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
-            if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
-              n = (*nnIt_i).second;
-              if (!nodesRecur.insert(n).second) {
-                // error: recursive dependancy
-                stopRecur = true;
-              }
-            }
-            else
-              stopRecur = true;
-          }
+          newElemDefs[i].SetID( elem->GetID() );
+          mesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
+          if ( !keepElem ) rmElemIds.pop_back();
+        }
+        else
+        {
+          newElemDefs[i].SetID( -1 );
         }
-        // BUG 0020185: end
+        SMDS_MeshElement* newElem = this->AddElement( newElemDefs[i].myNodes, newElemDefs[i] );
+        if ( sm && newElem )
+          sm->AddElement( newElem );
+        if ( elem != newElem )
+          ReplaceElemInGroups( elem, newElem, mesh );
       }
-      curNodes[ iCur ] = n;
-      bool isUnique = nodeSet.insert( n ).second;
-      if ( isUnique )
-        uniqueNodes[ iUnique++ ] = n;
-      else
-        iRepl[ nbRepl++ ] = iCur;
-      iCur++;
     }
+  }
 
-    // Analyse element topology after replacement
+  // Remove bad elements, then equal nodes (order important)
+  Remove( rmElemIds, false );
+  Remove( rmNodeIds, true );
 
-    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()) {
+  return;
+}
 
-        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];
-          }
+//=======================================================================
+//function : applyMerge
+//purpose  : Compute new connectivity of an element after merging nodes
+//  \param [in] elems - the element
+//  \param [out] newElemDefs - definition(s) of result element(s)
+//  \param [inout] nodeNodeMap - nodes to merge
+//  \param [in] avoidMakingHoles - if true and and the element becomes invalid
+//              after merging (but not degenerated), removes nodes causing
+//              the invalidity from \a nodeNodeMap.
+//  \return bool - true if the element should be removed
+//=======================================================================
 
-          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];
-              }
-              SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
-              myLastCreatedElems.Append(newElem);
-              if (aShapeId)
-                aMesh->SetMeshElementOnShape(newElem, aShapeId);
-            }
+bool SMESH_MeshEditor::applyMerge( const SMDS_MeshElement* elem,
+                                   vector< ElemFeatures >& newElemDefs,
+                                   TNodeNodeMap&           nodeNodeMap,
+                                   const bool              avoidMakingHoles )
+{
+  bool toRemove = false; // to remove elem
+  int nbResElems = 1;    // nb new elements
 
-            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());
-          }
+  newElemDefs.resize(nbResElems);
+  newElemDefs[0].Init( elem );
+  newElemDefs[0].myNodes.clear();
 
-        }
-        else if (elem->GetType() == SMDSAbs_Volume) {
-          // Polyhedral volume
-          if (nbUniqueNodes < 4) {
-            rmElemIds.push_back(elem->GetID());
-          }
-          else {
-            // each face has to be analyzed in order to check volume validity
-            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;
-
-              for (int iface = 1; iface <= nbFaces; iface++) {
-                int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
-                vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
-
-                for (int inode = 1; inode <= nbFaceNodes; inode++) {
-                  const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
-                  TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
-                  if (nnIt != nodeNodeMap.end()) { // faceNode sticks
-                    faceNode = (*nnIt).second;
-                  }
-                  faceNodes[inode - 1] = faceNode;
-                }
+  set<const SMDS_MeshNode*> nodeSet;
+  vector< const SMDS_MeshNode*>   curNodes;
+  vector< const SMDS_MeshNode*> & uniqueNodes = newElemDefs[0].myNodes;
+  vector<int> iRepl;
 
-                SimplifyFace(faceNodes, poly_nodes, quantities);
-              }
+  const        int  nbNodes = elem->NbNodes();
+  SMDSAbs_EntityType entity = elem->GetEntityType();
 
-              if (quantities.size() > 3) {
-                // to be done: remove coincident faces
-              }
+  curNodes.resize( nbNodes );
+  uniqueNodes.resize( nbNodes );
+  iRepl.resize( nbNodes );
+  int iUnique = 0, iCur = 0, nbRepl = 0;
 
-              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());
-                }
-            }
-            else {
-              rmElemIds.push_back(elem->GetID());
-            }
-          }
-        }
-        else {
-        }
+  // Get new seq of nodes
 
-        continue;
-      } // poly element
-
-      // Regular elements
-      // TODO not all the possible cases are solved. Find something more generic?
-      switch ( nbNodes ) {
-      case 2: ///////////////////////////////////// EDGE
-        isOk = false; break;
-      case 3: ///////////////////////////////////// TRIANGLE
-        isOk = false; break;
-      case 4:
-        if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
-          isOk = false;
-        else { //////////////////////////////////// QUADRANGLE
-          if ( nbUniqueNodes < 3 )
-            isOk = false;
-          else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
-            isOk = false; // opposite nodes stick
-          //MESSAGE("isOk " << isOk);
-        }
-        break;
-      case 6: ///////////////////////////////////// PENTAHEDRON
-        if ( nbUniqueNodes == 4 ) {
-          // ---------------------------------> tetrahedron
-          if (nbRepl == 3 &&
-              iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
-            // all top nodes stick: reverse a bottom
-            uniqueNodes[ 0 ] = curNodes [ 1 ];
-            uniqueNodes[ 1 ] = curNodes [ 0 ];
-          }
-          else if (nbRepl == 3 &&
-                   iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
-            // all bottom nodes stick: set a top before
-            uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
-            uniqueNodes[ 0 ] = curNodes [ 3 ];
-            uniqueNodes[ 1 ] = curNodes [ 4 ];
-            uniqueNodes[ 2 ] = curNodes [ 5 ];
-          }
-          else if (nbRepl == 4 &&
-                   iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
-            // a lateral face turns into a line: reverse a bottom
-            uniqueNodes[ 0 ] = curNodes [ 1 ];
-            uniqueNodes[ 1 ] = curNodes [ 0 ];
-          }
-          else
-            isOk = false;
-        }
-        else if ( nbUniqueNodes == 5 ) {
-          // PENTAHEDRON --------------------> 2 tetrahedrons
-          if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
-            // a bottom node sticks with a linked top one
-            // 1.
-            SMDS_MeshElement* newElem =
-              aMesh->AddVolume(curNodes[ 3 ],
-                               curNodes[ 4 ],
-                               curNodes[ 5 ],
-                               curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
-            myLastCreatedElems.Append(newElem);
-            if ( aShapeId )
-              aMesh->SetMeshElementOnShape( newElem, aShapeId );
-            // 2. : reverse a bottom
-            uniqueNodes[ 0 ] = curNodes [ 1 ];
-            uniqueNodes[ 1 ] = curNodes [ 0 ];
-            nbUniqueNodes = 4;
-          }
-          else
-            isOk = false;
-        }
-        else
-          isOk = false;
-        break;
-      case 8: {
-        if(elem->IsQuadratic()) { // Quadratic quadrangle
-          //   1    5    2
-          //    +---+---+
-          //    |       |
-          //    |       |
-          //   4+       +6
-          //    |       |
-          //    |       |
-          //    +---+---+
-          //   0    7    3
-          isOk = false;
-          if(nbRepl==2) {
-            MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
-          }
-          if(nbRepl==3) {
-            MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
-            nbUniqueNodes = 6;
-            if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
-              uniqueNodes[0] = curNodes[0];
-              uniqueNodes[1] = curNodes[2];
-              uniqueNodes[2] = curNodes[3];
-              uniqueNodes[3] = curNodes[5];
-              uniqueNodes[4] = curNodes[6];
-              uniqueNodes[5] = curNodes[7];
-              isOk = true;
-            }
-            if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
-              uniqueNodes[0] = curNodes[0];
-              uniqueNodes[1] = curNodes[1];
-              uniqueNodes[2] = curNodes[2];
-              uniqueNodes[3] = curNodes[4];
-              uniqueNodes[4] = curNodes[5];
-              uniqueNodes[5] = curNodes[6];
-              isOk = true;
-            }
-            if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
-              uniqueNodes[0] = curNodes[1];
-              uniqueNodes[1] = curNodes[2];
-              uniqueNodes[2] = curNodes[3];
-              uniqueNodes[3] = curNodes[5];
-              uniqueNodes[4] = curNodes[6];
-              uniqueNodes[5] = curNodes[0];
-              isOk = true;
-            }
-            if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
-              uniqueNodes[0] = curNodes[0];
-              uniqueNodes[1] = curNodes[1];
-              uniqueNodes[2] = curNodes[3];
-              uniqueNodes[3] = curNodes[4];
-              uniqueNodes[4] = curNodes[6];
-              uniqueNodes[5] = curNodes[7];
-              isOk = true;
-            }
-            if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
-              uniqueNodes[0] = curNodes[0];
-              uniqueNodes[1] = curNodes[2];
-              uniqueNodes[2] = curNodes[3];
-              uniqueNodes[3] = curNodes[1];
-              uniqueNodes[4] = curNodes[6];
-              uniqueNodes[5] = curNodes[7];
-              isOk = true;
-            }
-            if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
-              uniqueNodes[0] = curNodes[0];
-              uniqueNodes[1] = curNodes[1];
-              uniqueNodes[2] = curNodes[2];
-              uniqueNodes[3] = curNodes[4];
-              uniqueNodes[4] = curNodes[5];
-              uniqueNodes[5] = curNodes[7];
-              isOk = true;
-            }
-            if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
-              uniqueNodes[0] = curNodes[0];
-              uniqueNodes[1] = curNodes[1];
-              uniqueNodes[2] = curNodes[3];
-              uniqueNodes[3] = curNodes[4];
-              uniqueNodes[4] = curNodes[2];
-              uniqueNodes[5] = curNodes[7];
-              isOk = true;
-            }
-            if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
-              uniqueNodes[0] = curNodes[0];
-              uniqueNodes[1] = curNodes[1];
-              uniqueNodes[2] = curNodes[2];
-              uniqueNodes[3] = curNodes[4];
-              uniqueNodes[4] = curNodes[5];
-              uniqueNodes[5] = curNodes[3];
-              isOk = true;
-            }
-          }
-          if(nbRepl==4) {
-            MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
-          }
-          if(nbRepl==5) {
-            MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
+  SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+  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 = (*nnIt).second;
+    }
+    curNodes[ iCur ] = n;
+    bool isUnique = nodeSet.insert( n ).second;
+    if ( isUnique )
+      uniqueNodes[ iUnique++ ] = n;
+    else
+      iRepl[ nbRepl++ ] = iCur;
+    iCur++;
+  }
+
+  // Analyse element topology after replacement
+
+  int nbUniqueNodes = nodeSet.size();
+  if ( nbNodes != nbUniqueNodes ) // some nodes stick
+  {
+    toRemove = true;
+    nbResElems = 0;
+
+    if ( elem->IsQuadratic() && newElemDefs[0].myType == SMDSAbs_Face && nbNodes > 6 )
+    {
+      // if corner nodes stick, remove medium nodes between them from uniqueNodes
+      int nbCorners = nbNodes / 2;
+      for ( int iCur = 0; iCur < nbCorners; ++iCur )
+      {
+        int iPrev = ( iCur + 1 ) % nbCorners;
+        if ( curNodes[ iCur ] == curNodes[ iPrev ] ) // corners stick
+        {
+          int iMedium = iCur + nbCorners;
+          vector< const SMDS_MeshNode* >::iterator i =
+            std::find( uniqueNodes.begin() + nbCorners - nbRepl,
+                       uniqueNodes.end(),
+                       curNodes[ iMedium ]);
+          if ( i != uniqueNodes.end() )
+          {
+            --nbUniqueNodes;
+            for ( ; i+1 != uniqueNodes.end(); ++i )
+              *i = *(i+1);
           }
-          break;
         }
-        //////////////////////////////////// HEXAHEDRON
-        isOk = false;
-        SMDS_VolumeTool hexa (elem);
-        hexa.SetExternalNormal();
-        if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
-          //////////////////////// HEX ---> 1 tetrahedron
-          for ( int iFace = 0; iFace < 6; iFace++ ) {
-            const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
-            if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
-                curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
-                curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
-              // one face turns into a point ...
-              int iOppFace = hexa.GetOppFaceIndex( iFace );
-              ind = hexa.GetFaceNodesIndices( iOppFace );
-              int nbStick = 0;
-              for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
-                if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
-                  nbStick++;
-              }
-              if ( nbStick == 1 ) {
-                // ... and the opposite one - into a triangle.
-                // set a top node
-                ind = hexa.GetFaceNodesIndices( iFace );
-                uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
-                isOk = true;
-              }
-              break;
+      }
+    }
+
+    switch ( entity )
+    {
+    case SMDSEntity_Polygon:
+    case SMDSEntity_Quad_Polygon: // Polygon
+    {
+      ElemFeatures* elemType = & newElemDefs[0];
+      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;
+      nbResElems = SimplifyFace( curNodes, polygons_nodes, quantities );
+      newElemDefs.resize( nbResElems );
+      for ( int inode = 0, iface = 0; iface < nbResElems; iface++ )
+      {
+        ElemFeatures* elemType = & newElemDefs[iface];
+        if ( iface ) elemType->Init( elem );
+
+        vector<const SMDS_MeshNode *>& face_nodes = elemType->myNodes;
+        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 );
+        }
+        elemType->SetPoly(( nbNewNodes / ( elemType->myIsQuad + 1 ) > 4 ));
+      }
+      nbUniqueNodes = newElemDefs[0].myNodes.size();
+      break;
+    } // Polygon
+
+    case SMDSEntity_Polyhedra: // Polyhedral volume
+    {
+      if ( nbUniqueNodes >= 4 )
+      {
+        // each face has to be analyzed in order to check volume validity
+        if ( const SMDS_VtkVolume* aPolyedre = dynamic_cast<const SMDS_VtkVolume*>( elem ))
+        {
+          int nbFaces = aPolyedre->NbFaces();
+
+          vector<const SMDS_MeshNode *>& poly_nodes = newElemDefs[0].myNodes;
+          vector<int>                  & quantities = newElemDefs[0].myPolyhedQuantities;
+          vector<const SMDS_MeshNode *>  faceNodes;
+          poly_nodes.clear();
+          quantities.clear();
+
+          for (int iface = 1; iface <= nbFaces; iface++)
+          {
+            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
+            faceNodes.resize( nbFaceNodes );
+            for (int inode = 1; inode <= nbFaceNodes; inode++)
+            {
+              const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
+              TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
+              if ( nnIt != nodeNodeMap.end() ) // faceNode sticks
+                faceNode = (*nnIt).second;
+              faceNodes[inode - 1] = faceNode;
             }
+            SimplifyFace(faceNodes, poly_nodes, quantities);
           }
-        }
-        else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
-          //////////////////////// HEX ---> 1 prism
-          int nbTria = 0, iTria[3];
-          const int *ind; // indices of face nodes
-          // look for triangular faces
-          for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
-            ind = hexa.GetFaceNodesIndices( iFace );
-            TIDSortedNodeSet faceNodes;
-            for ( iCur = 0; iCur < 4; iCur++ )
-              faceNodes.insert( curNodes[ind[iCur]] );
-            if ( faceNodes.size() == 3 )
-              iTria[ nbTria++ ] = iFace;
-          }
-          // check if triangles are opposite
-          if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
+
+          if ( quantities.size() > 3 )
           {
-            isOk = true;
-            // set nodes of the bottom triangle
-            ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
-            vector<int> indB;
-            for ( iCur = 0; iCur < 4; iCur++ )
-              if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
-                indB.push_back( ind[iCur] );
-            if ( !hexa.IsForward() )
-              std::swap( indB[0], indB[2] );
-            for ( iCur = 0; iCur < 3; iCur++ )
-              uniqueNodes[ iCur ] = curNodes[indB[iCur]];
-            // set nodes of the top triangle
-            const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
-            for ( iCur = 0; iCur < 3; ++iCur )
-              for ( int j = 0; j < 4; ++j )
-                if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
-                {
-                  uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
-                  break;
-                }
+            // TODO: remove coincident faces
+            nbResElems = 1;
+            nbUniqueNodes = newElemDefs[0].myNodes.size();
           }
-          break;
         }
-        else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
-          //////////////////// HEXAHEDRON ---> 2 tetrahedrons
-          for ( int iFace = 0; iFace < 6; iFace++ ) {
-            const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
-            if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
-                curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
-                curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
-              // one face turns into a point ...
-              int iOppFace = hexa.GetOppFaceIndex( iFace );
-              ind = hexa.GetFaceNodesIndices( iOppFace );
-              int nbStick = 0;
-              iUnique = 2;  // reverse a tetrahedron 1 bottom
-              for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
-                if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
-                  nbStick++;
-                else if ( iUnique >= 0 )
-                  uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
-              }
-              if ( nbStick == 0 ) {
-                // ... and the opposite one is a quadrangle
-                // set a top node
-                const int* indTop = hexa.GetFaceNodesIndices( iFace );
-                uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
-                nbUniqueNodes = 4;
-                // tetrahedron 2
-                SMDS_MeshElement* newElem =
-                  aMesh->AddVolume(curNodes[ind[ 0 ]],
-                                   curNodes[ind[ 3 ]],
-                                   curNodes[ind[ 2 ]],
-                                   curNodes[indTop[ 0 ]]);
-                myLastCreatedElems.Append(newElem);
-                if ( aShapeId )
-                  aMesh->SetMeshElementOnShape( newElem, aShapeId );
-                isOk = true;
-              }
-              break;
-            }
-          }
+      }
+    }
+    break;
+
+    // Regular elements
+    // TODO not all the possible cases are solved. Find something more generic?
+    case SMDSEntity_Edge: //////// EDGE
+    case SMDSEntity_Triangle: //// TRIANGLE
+    case SMDSEntity_Quad_Triangle:
+    case SMDSEntity_Tetra:
+    case SMDSEntity_Quad_Tetra: // TETRAHEDRON
+    {
+      break;
+    }
+    case SMDSEntity_Quad_Edge:
+    {
+      break;
+    }
+    case SMDSEntity_Quadrangle: //////////////////////////////////// QUADRANGLE
+    {
+      if ( nbUniqueNodes < 3 )
+        toRemove = true;
+      else if ( nbRepl == 1 && curNodes[ iRepl[0]] == curNodes[( iRepl[0]+2 )%4 ])
+        toRemove = true; // opposite nodes stick
+      else
+        toRemove = false;
+      break;
+    }
+    case SMDSEntity_Quad_Quadrangle: // Quadratic QUADRANGLE
+    {
+      //   1    5    2
+      //    +---+---+
+      //    |       |
+      //   4+       +6
+      //    |       |
+      //    +---+---+
+      //   0    7    3
+      if ( nbUniqueNodes == 6 &&
+           iRepl[0] < 4       &&
+           ( nbRepl == 1 || iRepl[1] >= 4 ))
+      {
+        toRemove = false;
+      }
+      break;
+    }
+    case SMDSEntity_BiQuad_Quadrangle: // Bi-Quadratic QUADRANGLE
+    {
+      //   1    5    2
+      //    +---+---+
+      //    |       |
+      //   4+  8+   +6
+      //    |       |
+      //    +---+---+
+      //   0    7    3
+      if (( nbUniqueNodes == 7 && nbRepl == 2 && iRepl[1] != 8 ) &&
+          (( iRepl[0] == 1 && iRepl[1] == 4 && curNodes[1] == curNodes[0] ) ||
+           ( iRepl[0] == 2 && iRepl[1] == 5 && curNodes[2] == curNodes[1] ) ||
+           ( iRepl[0] == 3 && iRepl[1] == 6 && curNodes[3] == curNodes[2] ) ||
+           ( iRepl[0] == 3 && iRepl[1] == 7 && curNodes[3] == curNodes[0] )))
+      {
+        toRemove = false;
+      }
+      break;
+    }
+    case SMDSEntity_Penta: ///////////////////////////////////// PENTAHEDRON
+    {
+      if ( nbUniqueNodes == 4 ) {
+        // ---------------------------------> tetrahedron
+        if ( curNodes[3] == curNodes[4] &&
+             curNodes[3] == curNodes[5] ) {
+          // top nodes stick
+          toRemove = false;
+        }
+        else if ( curNodes[0] == curNodes[1] &&
+                  curNodes[0] == curNodes[2] ) {
+          // bottom nodes stick: set a top before
+          uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
+          uniqueNodes[ 0 ] = curNodes [ 5 ];
+          uniqueNodes[ 1 ] = curNodes [ 4 ];
+          uniqueNodes[ 2 ] = curNodes [ 3 ];
+          toRemove = false;
+        }
+        else if (( curNodes[0] == curNodes[3] ) +
+                 ( curNodes[1] == curNodes[4] ) +
+                 ( curNodes[2] == curNodes[5] ) == 2 ) {
+          // a lateral face turns into a line
+          toRemove = false;
+        }
+      }
+      else if ( nbUniqueNodes == 5 ) {
+        // PENTAHEDRON --------------------> pyramid
+        if ( curNodes[0] == curNodes[3] )
+        {
+          uniqueNodes[ 0 ] = curNodes[ 1 ];
+          uniqueNodes[ 1 ] = curNodes[ 4 ];
+          uniqueNodes[ 2 ] = curNodes[ 5 ];
+          uniqueNodes[ 3 ] = curNodes[ 2 ];
+          uniqueNodes[ 4 ] = curNodes[ 0 ];
+          toRemove = false;
+        }
+        if ( curNodes[1] == curNodes[4] )
+        {
+          uniqueNodes[ 0 ] = curNodes[ 0 ];
+          uniqueNodes[ 1 ] = curNodes[ 2 ];
+          uniqueNodes[ 2 ] = curNodes[ 5 ];
+          uniqueNodes[ 3 ] = curNodes[ 3 ];
+          uniqueNodes[ 4 ] = curNodes[ 1 ];
+          toRemove = false;
+        }
+        if ( curNodes[2] == curNodes[5] )
+        {
+          uniqueNodes[ 0 ] = curNodes[ 0 ];
+          uniqueNodes[ 1 ] = curNodes[ 3 ];
+          uniqueNodes[ 2 ] = curNodes[ 4 ];
+          uniqueNodes[ 3 ] = curNodes[ 1 ];
+          uniqueNodes[ 4 ] = curNodes[ 2 ];
+          toRemove = false;
         }
-        else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
-          ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
-          // find indices of quad and tri faces
-          int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
-          for ( iFace = 0; iFace < 6; iFace++ ) {
-            const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
-            nodeSet.clear();
-            for ( iCur = 0; iCur < 4; iCur++ )
-              nodeSet.insert( curNodes[ind[ iCur ]] );
-            nbUniqueNodes = nodeSet.size();
-            if ( nbUniqueNodes == 3 )
-              iTriFace[ nbTri++ ] = iFace;
-            else if ( nbUniqueNodes == 4 )
-              iQuadFace[ nbQuad++ ] = iFace;
-          }
-          if (nbQuad == 2 && nbTri == 4 &&
-              hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
-            // 2 opposite quadrangles stuck with a diagonal;
-            // sample groups of merged indices: (0-4)(2-6)
-            // --------------------------------------------> 2 tetrahedrons
-            const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
-            const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
-            int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
-            if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
-                curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
-              // stuck with 0-2 diagonal
-              i0  = ind1[ 3 ];
-              i1d = ind1[ 0 ];
-              i2  = ind1[ 1 ];
-              i3d = ind1[ 2 ];
-              i0t = ind2[ 1 ];
-              i2t = ind2[ 3 ];
-            }
-            else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
-                     curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
-              // stuck with 1-3 diagonal
-              i0  = ind1[ 0 ];
-              i1d = ind1[ 1 ];
-              i2  = ind1[ 2 ];
-              i3d = ind1[ 3 ];
-              i0t = ind2[ 0 ];
-              i2t = ind2[ 1 ];
+      }
+      break;
+    }
+    case SMDSEntity_Hexa:
+    {
+      //////////////////////////////////// HEXAHEDRON
+      SMDS_VolumeTool hexa (elem);
+      hexa.SetExternalNormal();
+      if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
+        //////////////////////// HEX ---> tetrahedron
+        for ( int iFace = 0; iFace < 6; iFace++ ) {
+          const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
+          if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
+              curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
+              curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
+            // one face turns into a point ...
+            int  pickInd = ind[ 0 ];
+            int iOppFace = hexa.GetOppFaceIndex( iFace );
+            ind = hexa.GetFaceNodesIndices( iOppFace );
+            int nbStick = 0;
+            uniqueNodes.clear();
+            for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
+              if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
+                nbStick++;
+              else
+                uniqueNodes.push_back( curNodes[ind[ iCur ]]);
             }
-            else {
-              ASSERT(0);
+            if ( nbStick == 1 ) {
+              // ... and the opposite one - into a triangle.
+              // set a top node
+              uniqueNodes.push_back( curNodes[ pickInd ]);
+              toRemove = false;
             }
-            // tetrahedron 1
-            uniqueNodes[ 0 ] = curNodes [ i0 ];
-            uniqueNodes[ 1 ] = curNodes [ i1d ];
-            uniqueNodes[ 2 ] = curNodes [ i3d ];
-            uniqueNodes[ 3 ] = curNodes [ i0t ];
-            nbUniqueNodes = 4;
-            // tetrahedron 2
-            SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
-                                                         curNodes[ i2 ],
-                                                         curNodes[ i3d ],
-                                                         curNodes[ i2t ]);
-            myLastCreatedElems.Append(newElem);
-            if ( aShapeId )
-              aMesh->SetMeshElementOnShape( newElem, aShapeId );
-            isOk = true;
+            break;
           }
-          else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
-                   ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
-            // --------------------------------------------> prism
-            // find 2 opposite triangles
-            nbUniqueNodes = 6;
-            for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
-              if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
-                // find indices of kept and replaced nodes
-                // and fill unique nodes of 2 opposite triangles
-                const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
-                const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
-                const SMDS_MeshNode** hexanodes = hexa.GetNodes();
-                // fill unique nodes
-                iUnique = 0;
-                isOk = true;
-                for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
-                  const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
-                  const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
-                  if ( n == nInit ) {
-                    // iCur of a linked node of the opposite face (make normals co-directed):
-                    int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
-                    // check that correspondent corners of triangles are linked
-                    if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
-                      isOk = false;
-                    else {
-                      uniqueNodes[ iUnique ] = n;
-                      uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
-                      iUnique++;
-                    }
-                  }
-                }
+        }
+      }
+      else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
+        //////////////////////// HEX ---> prism
+        int nbTria = 0, iTria[3];
+        const int *ind; // indices of face nodes
+        // look for triangular faces
+        for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
+          ind = hexa.GetFaceNodesIndices( iFace );
+          TIDSortedNodeSet faceNodes;
+          for ( iCur = 0; iCur < 4; iCur++ )
+            faceNodes.insert( curNodes[ind[iCur]] );
+          if ( faceNodes.size() == 3 )
+            iTria[ nbTria++ ] = iFace;
+        }
+        // check if triangles are opposite
+        if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
+        {
+          // set nodes of the bottom triangle
+          ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
+          vector<int> indB;
+          for ( iCur = 0; iCur < 4; iCur++ )
+            if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
+              indB.push_back( ind[iCur] );
+          if ( !hexa.IsForward() )
+            std::swap( indB[0], indB[2] );
+          for ( iCur = 0; iCur < 3; iCur++ )
+            uniqueNodes[ iCur ] = curNodes[indB[iCur]];
+          // set nodes of the top triangle
+          const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
+          for ( iCur = 0; iCur < 3; ++iCur )
+            for ( int j = 0; j < 4; ++j )
+              if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
+              {
+                uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
                 break;
               }
+          toRemove = false;
+          break;
+        }
+      }
+      else if (nbUniqueNodes == 5 && nbRepl == 3 ) {
+        //////////////////// HEXAHEDRON ---> pyramid
+        for ( int iFace = 0; iFace < 6; iFace++ ) {
+          const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
+          if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
+              curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
+              curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
+            // one face turns into a point ...
+            int iOppFace = hexa.GetOppFaceIndex( iFace );
+            ind = hexa.GetFaceNodesIndices( iOppFace );
+            uniqueNodes.clear();
+            for ( iCur = 0; iCur < 4; iCur++ ) {
+              if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
+                break;
+              else
+                uniqueNodes.push_back( curNodes[ind[ iCur ]]);
+            }
+            if ( uniqueNodes.size() == 4 ) {
+              // ... and the opposite one is a quadrangle
+              // set a top node
+              const int* indTop = hexa.GetFaceNodesIndices( iFace );
+              uniqueNodes.push_back( curNodes[indTop[ 0 ]]);
+              toRemove = false;
             }
+            break;
           }
-        } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
-        else
-        {
-          MESSAGE("MergeNodes() removes hexahedron "<< elem);
         }
-        break;
-      } // HEXAHEDRON
-
-      default:
-        isOk = false;
-      } // switch ( nbNodes )
-
-    } // 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);
-            }
+      if ( toRemove && nbUniqueNodes > 4 ) {
+        ////////////////// HEXAHEDRON ---> polyhedron
+        hexa.SetExternalNormal();
+        vector<const SMDS_MeshNode *>& poly_nodes = newElemDefs[0].myNodes;
+        vector<int>                  & quantities = newElemDefs[0].myPolyhedQuantities;
+        poly_nodes.reserve( 6 * 4 ); poly_nodes.clear();
+        quantities.reserve( 6 );     quantities.clear();
+        for ( int iFace = 0; iFace < 6; iFace++ )
+        {
+          const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
+          if ( curNodes[ind[0]] == curNodes[ind[2]] ||
+               curNodes[ind[1]] == curNodes[ind[3]] )
+          {
+            quantities.clear();
+            break; // opposite nodes stick
+          }
+          nodeSet.clear();
+          for ( iCur = 0; iCur < 4; iCur++ )
+          {
+            if ( nodeSet.insert( curNodes[ind[ iCur ]] ).second )
+              poly_nodes.push_back( curNodes[ind[ iCur ]]);
           }
-          aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
+          if ( nodeSet.size() < 3 )
+            poly_nodes.resize( poly_nodes.size() - nodeSet.size() );
+          else
+            quantities.push_back( nodeSet.size() );
+        }
+        if ( quantities.size() >= 4 )
+        {
+          nbResElems = 1;
+          nbUniqueNodes = poly_nodes.size();
+          newElemDefs[0].SetPoly(true);
         }
       }
-      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);
+      break;
+    } // case HEXAHEDRON
 
-        SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
+    default:
+      toRemove = true;
 
-        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 );
-      }
-    }
-    else {
-      // Remove invalid regular element or invalid polygon
-      rmElemIds.push_back( elem->GetID() );
+    } // switch ( entity )
+
+    if ( toRemove && nbResElems == 0 && avoidMakingHoles )
+    {
+      // erase from nodeNodeMap nodes whose merge spoils elem
+      vector< const SMDS_MeshNode* > noMergeNodes;
+      SMESH_MeshAlgos::DeMerge( elem, curNodes, noMergeNodes );
+      for ( size_t i = 0; i < noMergeNodes.size(); ++i )
+        nodeNodeMap.erase( noMergeNodes[i] );
     }
+    
+  } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
 
-  } // loop on elements
+  uniqueNodes.resize( nbUniqueNodes );
 
-  // Remove bad elements, then equal nodes (order important)
+  if ( !toRemove && nbResElems == 0 )
+    nbResElems = 1;
 
-  Remove( rmElemIds, false );
-  Remove( rmNodeIds, true );
+  newElemDefs.resize( nbResElems );
 
+  return !toRemove;
 }
 
 
@@ -7026,10 +7963,6 @@ public:
   const SMDS_MeshElement* Get() const
   { return myElem; }
 
-  void Set(const SMDS_MeshElement* e) const
-  { myElem = e; }
-
-
 private:
   mutable const SMDS_MeshElement* myElem;
 };
@@ -7053,7 +7986,7 @@ void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet &        theElements,
   { // get all elements in the mesh
     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
     while ( eIt->more() )
-      theElements.insert( theElements.end(), eIt->next());
+      theElements.insert( theElements.end(), eIt->next() );
   }
 
   vector< TGroupOfElems > arrayOfGroups;
@@ -7061,31 +7994,32 @@ void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet &        theElements,
   TMapOfNodeSet mapOfNodeSet;
 
   TIDSortedElemSet::iterator elemIt = theElements.begin();
-  for ( int i = 0, j=0; elemIt != theElements.end(); ++elemIt, ++j ) {
+  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 );
     }
   }
 }
@@ -7156,6 +8090,24 @@ static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
   return SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet );
 }
 
+//=======================================================================
+//function : findSegment
+//purpose  : Return a mesh segment by two nodes one of which can be medium
+//=======================================================================
+
+static const SMDS_MeshElement* findSegment(const SMDS_MeshNode* n1,
+                                           const SMDS_MeshNode* n2)
+{
+  SMDS_ElemIteratorPtr it = n1->GetInverseElementIterator( SMDSAbs_Edge );
+  while ( it->more() )
+  {
+    const SMDS_MeshElement* seg = it->next();
+    if ( seg->GetNodeIndex( n2 ) >= 0 )
+      return seg;
+  }
+  return 0;
+}
+
 //=======================================================================
 //function : FindFreeBorder
 //purpose  :
@@ -7180,7 +8132,6 @@ bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirst
   theNodes.push_back( theFirstNode );
   theNodes.push_back( theSecondNode );
 
-  //vector<const SMDS_MeshNode*> nodes;
   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
   TIDSortedElemSet foundElems;
   bool needTheLast = ( theLastNode != 0 );
@@ -7192,17 +8143,16 @@ bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirst
     // find all free border faces sharing form nStart
 
     list< const SMDS_MeshElement* > curElemList;
-    list< const SMDS_MeshNode* > nStartList;
+    list< const SMDS_MeshNode* >    nStartList;
     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
     while ( invElemIt->more() ) {
       const SMDS_MeshElement* e = invElemIt->next();
       if ( e == curElem || foundElems.insert( e ).second ) {
         // get nodes
         int iNode = 0, nbNodes = e->NbNodes();
-        //const SMDS_MeshNode* nodes[nbNodes+1];
         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
 
-        if(e->IsQuadratic()) {
+        if ( e->IsQuadratic() ) {
           const SMDS_VtkFace* F =
             dynamic_cast<const SMDS_VtkFace*>(e);
           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
@@ -7319,6 +8269,8 @@ bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
 //=======================================================================
 //function : SewFreeBorder
 //purpose  :
+//warning  : for border-to-side sewing theSideSecondNode is considered as
+//           the last side node and theSideThirdNode is not used
 //=======================================================================
 
 SMESH_MeshEditor::Sew_Error
@@ -7335,16 +8287,15 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
-  MESSAGE("::SewFreeBorder()");
   Sew_Error aResult = SEW_OK;
 
   // ====================================
   //    find side nodes and elements
   // ====================================
 
-  list< const SMDS_MeshNode* > nSide[ 2 ];
+  list< const SMDS_MeshNode* >    nSide[ 2 ];
   list< const SMDS_MeshElement* > eSide[ 2 ];
-  list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
+  list< const SMDS_MeshNode* >::iterator    nIt[ 2 ];
   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
 
   // Free border 1
@@ -7380,7 +8331,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
     // -------------------------------------------------------------------------
 
     // 1. Since sewing may break if there are volumes to split on the side 2,
-    //    we wont move nodes but just compute new coordinates for them
+    //    we won't move nodes but just compute new coordinates for them
     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
     TNodeXYZMap nBordXYZ;
     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
@@ -7443,7 +8394,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
     //const SMDS_MeshNode* faceNodes[ 4 ];
 
     const SMDS_MeshNode*    sideNode;
-    const SMDS_MeshElement* sideElem;
+    const SMDS_MeshElement* sideElem  = 0;
     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
     nBordIt = bordNodes.begin();
@@ -7468,7 +8419,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
       {
         const SMDS_MeshElement* elem = invElemIt->next();
         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
-        int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
+        int iPrevNode = 0, iNode = 0, nbNodes = elem->NbNodes();
         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
         bool isVolume = volume.Set( elem );
         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
@@ -7544,7 +8495,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
       } // loop on inverse elements of prevSideNode
 
       if ( !sideNode ) {
-        MESSAGE(" Cant find path by links of the Side 2 ");
+        MESSAGE(" Can't find path by links of the Side 2 ");
         return SEW_BAD_SIDE_NODES;
       }
       sideNodes.push_back( sideNode );
@@ -7580,12 +8531,26 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
   // sew the border to the side 2
   // ============================
 
-  int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
+  int nbNodes[]  = { (int)nSide[0].size(), (int)nSide[1].size() };
   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
 
+  bool toMergeConformal = ( nbNodes[0] == nbNodes[1] );
+  if ( toMergeConformal && toCreatePolygons )
+  {
+    // do not merge quadrangles if polygons are OK (IPAL0052824)
+    eIt[0] = eSide[0].begin();
+    eIt[1] = eSide[1].begin();
+    bool allQuads[2] = { true, true };
+    for ( int iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
+      for ( ; allQuads[iBord] && eIt[iBord] != eSide[iBord].end(); ++eIt[iBord] )
+        allQuads[iBord] = ( (*eIt[iBord])->NbCornerNodes() == 4 );
+    }
+    toMergeConformal = ( !allQuads[0] && !allQuads[1] );
+  }
+
   TListOfListOfNodes nodeGroupsToMerge;
-  if ( nbNodes[0] == nbNodes[1] ||
-       ( theSideIsFreeBorder && !theSideThirdNode)) {
+  if (( toMergeConformal ) ||
+      ( theSideIsFreeBorder && !theSideThirdNode )) {
 
     // all nodes are to be merged
 
@@ -7603,10 +8568,9 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
     // insert new nodes into the border and the side to get equal nb of segments
 
     // get normalized parameters of nodes on the borders
-    //double param[ 2 ][ maxNbNodes ];
-    double* param[ 2 ];
-    param[0] = new double [ maxNbNodes ];
-    param[1] = new double [ maxNbNodes ];
+    vector< double > param[ 2 ];
+    param[0].resize( maxNbNodes );
+    param[1].resize( maxNbNodes );
     int iNode, iBord;
     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
@@ -7651,8 +8615,8 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
         if ( i[ iBord ] > 0 )
           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
       }
-      double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
-      double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
+      double  minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
+      double  maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
 
       // choose to insert or to merge nodes
@@ -7676,10 +8640,10 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
         // insert
         // ------
         int intoBord = ( du < 0 ) ? 0 : 1;
-        const SMDS_MeshElement* elem = *eIt[ intoBord ];
+        const SMDS_MeshElement* elem = *eIt [ intoBord ];
         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
-        const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
-        const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
+        const SMDS_MeshNode*    n2   = *nIt [ intoBord ];
+        const SMDS_MeshNode*    nIns = *nIt [ 1 - intoBord ];
         if ( intoBord == 1 ) {
           // move node of the border to be on a link of elem of the side
           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
@@ -7689,7 +8653,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
         }
         insertMapIt = insertMap.find( elem );
-        bool notFound = ( insertMapIt == insertMap.end() );
+        bool  notFound = ( insertMapIt == insertMap.end() );
         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
         if ( otherLink ) {
           // insert into another link of the same element:
@@ -7699,12 +8663,11 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
           // 2. perform insertion into the link of adjacent faces
-          while (true) {
-            const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
-            if ( adjElem )
-              InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
-            else
-              break;
+          while ( const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem )) {
+            InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
+          }
+          while ( const SMDS_MeshElement* seg = findSegment( n12, n22 )) {
+            InsertNodesIntoLink( seg, n12, n22, nodeList );
           }
           if (toCreatePolyedrs) {
             // perform insertion into the links of adjacent volumes
@@ -7716,8 +8679,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
         }
         if ( notFound || otherLink ) {
           // add element and nodes of the side into the insertMap
-          insertMapIt = insertMap.insert
-            ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
+          insertMapIt = insertMap.insert( make_pair( elem, list<const SMDS_MeshNode*>() )).first;
           (*insertMapIt).second.push_back( n1 );
           (*insertMapIt).second.push_back( n2 );
         }
@@ -7751,14 +8713,14 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
 
       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
 
+      while ( const SMDS_MeshElement* seg = findSegment( n1, n2 )) {
+        InsertNodesIntoLink( seg, n1, n2, nodeList );
+      }
+
       if ( !theSideIsFreeBorder ) {
         // look for and insert nodes into the faces adjacent to elem
-        while (true) {
-          const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
-          if ( adjElem )
-            InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
-          else
-            break;
+        while ( const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem )) {
+          InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
         }
       }
       if (toCreatePolyedrs) {
@@ -7766,69 +8728,155 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
         UpdateVolumes(n1, n2, nodeList);
       }
     }
-
-    delete param[0];
-    delete param[1];
   } // end: insert new nodes
 
   MergeNodes ( nodeGroupsToMerge );
 
+
+  // Remove coincident segments
+
+  // get new segments
+  TIDSortedElemSet segments;
+  SMESH_SequenceOfElemPtr newFaces;
+  for ( int i = 1; i <= myLastCreatedElems.Length(); ++i )
+  {
+    if ( !myLastCreatedElems(i) ) continue;
+    if ( myLastCreatedElems(i)->GetType() == SMDSAbs_Edge )
+      segments.insert( segments.end(), myLastCreatedElems(i) );
+    else
+      newFaces.Append( myLastCreatedElems(i) );
+  }
+  // get segments adjacent to merged nodes
+  TListOfListOfNodes::iterator groupIt = nodeGroupsToMerge.begin();
+  for ( ; groupIt != nodeGroupsToMerge.end(); groupIt++ )
+  {
+    const list<const SMDS_MeshNode*>& nodes = *groupIt;
+    SMDS_ElemIteratorPtr segIt = nodes.front()->GetInverseElementIterator( SMDSAbs_Edge );
+    while ( segIt->more() )
+      segments.insert( segIt->next() );
+  }
+
+  // find coincident
+  TListOfListOfElementsID equalGroups;
+  if ( !segments.empty() )
+    FindEqualElements( segments, equalGroups );
+  if ( !equalGroups.empty() )
+  {
+    // remove from segments those that will be removed
+    TListOfListOfElementsID::iterator itGroups = equalGroups.begin();
+    for ( ; itGroups != equalGroups.end(); ++itGroups )
+    {
+      list< int >& group = *itGroups;
+      list< int >::iterator id = group.begin();
+      for ( ++id; id != group.end(); ++id )
+        if ( const SMDS_MeshElement* seg = GetMeshDS()->FindElement( *id ))
+          segments.erase( seg );
+    }
+    // remove equal segments
+    MergeElements( equalGroups );
+
+    // restore myLastCreatedElems
+    myLastCreatedElems = newFaces;
+    TIDSortedElemSet::iterator seg = segments.begin();
+    for ( ; seg != segments.end(); ++seg )
+      myLastCreatedElems.Append( *seg );
+  }
+
   return aResult;
 }
 
 //=======================================================================
 //function : InsertNodesIntoLink
-//purpose  : insert theNodesToInsert into theFace between theBetweenNode1
+//purpose  : insert theNodesToInsert into theElement between theBetweenNode1
 //           and theBetweenNode2 and split theElement
 //=======================================================================
 
-void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
+void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theElement,
                                            const SMDS_MeshNode*        theBetweenNode1,
                                            const SMDS_MeshNode*        theBetweenNode2,
                                            list<const SMDS_MeshNode*>& theNodesToInsert,
                                            const bool                  toCreatePoly)
 {
+  if ( !theElement ) return;
+
+  SMESHDS_Mesh *aMesh = GetMeshDS();
+  vector<const SMDS_MeshElement*> newElems;
+
+  if ( theElement->GetType() == SMDSAbs_Edge )
+  {
+    theNodesToInsert.push_front( theBetweenNode1 );
+    theNodesToInsert.push_back ( theBetweenNode2 );
+    list<const SMDS_MeshNode*>::iterator n = theNodesToInsert.begin();
+    const SMDS_MeshNode* n1 = *n;
+    for ( ++n; n != theNodesToInsert.end(); ++n )
+    {
+      const SMDS_MeshNode* n2 = *n;
+      if ( const SMDS_MeshElement* seg = aMesh->FindEdge( n1, n2 ))
+        AddToSameGroups( seg, theElement, aMesh );
+      else
+        newElems.push_back( aMesh->AddEdge ( n1, n2 ));
+      n1 = n2;
+    }
+    theNodesToInsert.pop_front();
+    theNodesToInsert.pop_back();
+
+    if ( theElement->IsQuadratic() ) // add a not split part
+    {
+      vector<const SMDS_MeshNode*> nodes( theElement->begin_nodes(),
+                                          theElement->end_nodes() );
+      int iOther = 0, nbN = nodes.size();
+      for ( ; iOther < nbN; ++iOther )
+        if ( nodes[iOther] != theBetweenNode1 &&
+             nodes[iOther] != theBetweenNode2 )
+          break;
+      if      ( iOther == 0 )
+      {
+        if ( const SMDS_MeshElement* seg = aMesh->FindEdge( nodes[0], nodes[1] ))
+          AddToSameGroups( seg, theElement, aMesh );
+        else
+          newElems.push_back( aMesh->AddEdge ( nodes[0], nodes[1] ));
+      }
+      else if ( iOther == 2 )
+      {
+        if ( const SMDS_MeshElement* seg = aMesh->FindEdge( nodes[1], nodes[2] ))
+          AddToSameGroups( seg, theElement, aMesh );
+        else
+          newElems.push_back( aMesh->AddEdge ( nodes[1], nodes[2] ));
+      }
+    }
+    // treat new elements
+    for ( size_t i = 0; i < newElems.size(); ++i )
+      if ( newElems[i] )
+      {
+        aMesh->SetMeshElementOnShape( newElems[i], theElement->getshapeId() );
+        myLastCreatedElems.Append( newElems[i] );
+      }
+    ReplaceElemInGroups( theElement, newElems, aMesh );
+    aMesh->RemoveElement( theElement );
+    return;
+
+  } // if ( theElement->GetType() == SMDSAbs_Edge )
+
+  const SMDS_MeshElement* theFace = theElement;
   if ( theFace->GetType() != SMDSAbs_Face ) return;
 
   // find indices of 2 link nodes and of the rest nodes
   int iNode = 0, il1, il2, i3, i4;
   il1 = il2 = i3 = i4 = -1;
-  //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
 
-  if(theFace->IsQuadratic()) {
-    const SMDS_VtkFace* F =
-      dynamic_cast<const SMDS_VtkFace*>(theFace);
-    if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
-    // use special nodes iterator
-    SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
-    while( anIter->more() ) {
-      const SMDS_MeshNode* n = cast2Node(anIter->next());
-      if ( n == theBetweenNode1 )
-        il1 = iNode;
-      else if ( n == theBetweenNode2 )
-        il2 = iNode;
-      else if ( i3 < 0 )
-        i3 = iNode;
-      else
-        i4 = iNode;
-      nodes[ iNode++ ] = n;
-    }
-  }
-  else {
-    SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
-    while ( nodeIt->more() ) {
-      const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
-      if ( n == theBetweenNode1 )
-        il1 = iNode;
-      else if ( n == theBetweenNode2 )
-        il2 = iNode;
-      else if ( i3 < 0 )
-        i3 = iNode;
-      else
-        i4 = iNode;
-      nodes[ iNode++ ] = n;
-    }
+  SMDS_NodeIteratorPtr nodeIt = theFace->interlacedNodesIterator();
+  while ( nodeIt->more() ) {
+    const SMDS_MeshNode* n = nodeIt->next();
+    if ( n == theBetweenNode1 )
+      il1 = iNode;
+    else if ( n == theBetweenNode2 )
+      il2 = iNode;
+    else if ( i3 < 0 )
+      i3 = iNode;
+    else
+      i4 = iNode;
+    nodes[ iNode++ ] = n;
   }
   if ( il1 < 0 || il2 < 0 || i3 < 0 )
     return ;
@@ -7858,9 +8906,8 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
     // add nodes of face up to first node of link
     bool isFLN = false;
 
-    if(theFace->IsQuadratic()) {
-      const SMDS_VtkFace* F =
-        dynamic_cast<const SMDS_VtkFace*>(theFace);
+    if ( theFace->IsQuadratic() ) {
+      const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>(theFace);
       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
       // use special nodes iterator
       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
@@ -7902,28 +8949,12 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
       }
     }
 
-    // edit or replace the face
-    SMESHDS_Mesh *aMesh = GetMeshDS();
-
-    if (theFace->IsPoly()) {
-      aMesh->ChangePolygonNodes(theFace, poly_nodes);
-    }
-    else {
-      int aShapeId = FindShape( theFace );
-
-      SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
-      myLastCreatedElems.Append(newElem);
-      if ( aShapeId && newElem )
-        aMesh->SetMeshElementOnShape( newElem, aShapeId );
-
-      aMesh->RemoveElement(theFace);
-    }
-    return;
+    // make a new face
+    newElems.push_back( aMesh->AddPolygonalFace( poly_nodes ));
   }
 
-  SMESHDS_Mesh *aMesh = GetMeshDS();
-  if( !theFace->IsQuadratic() ) {
-
+  else if ( !theFace->IsQuadratic() )
+  {
     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
     int nbLinkNodes = 2 + aNodesToInsert.size();
     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
@@ -7936,7 +8967,7 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
     }
     // decide how to split a quadrangle: compare possible variants
     // and choose which of splits to be a quadrangle
-    int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
+    int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad = 0;
     if ( nbFaceNodes == 3 ) {
       iBestQuad = nbSplits;
       i4 = i3;
@@ -7972,41 +9003,32 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
     }
 
     // create new elements
-    int aShapeId = FindShape( theFace );
-
     i1 = 0; i2 = 1;
-    for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
-      SMDS_MeshElement* newElem = 0;
+    for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ )
+    {
       if ( iSplit == iBestQuad )
-        newElem = aMesh->AddFace (linkNodes[ i1++ ],
-                                  linkNodes[ i2++ ],
-                                  nodes[ i3 ],
-                                  nodes[ i4 ]);
+        newElems.push_back( aMesh->AddFace (linkNodes[ i1++ ],
+                                            linkNodes[ i2++ ],
+                                            nodes[ i3 ],
+                                            nodes[ i4 ]));
       else
-        newElem = aMesh->AddFace (linkNodes[ i1++ ],
-                                  linkNodes[ i2++ ],
-                                  nodes[ iSplit < iBestQuad ? i4 : i3 ]);
-      myLastCreatedElems.Append(newElem);
-      if ( aShapeId && newElem )
-        aMesh->SetMeshElementOnShape( newElem, aShapeId );
+        newElems.push_back( aMesh->AddFace (linkNodes[ i1++ ],
+                                            linkNodes[ i2++ ],
+                                            nodes[ iSplit < iBestQuad ? i4 : i3 ]));
     }
 
-    // change nodes of theFace
     const SMDS_MeshNode* newNodes[ 4 ];
     newNodes[ 0 ] = linkNodes[ i1 ];
     newNodes[ 1 ] = linkNodes[ i2 ];
     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
     newNodes[ 3 ] = nodes[ i4 ];
-    //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
-    const SMDS_MeshElement* newElem = 0;
     if (iSplit == iBestQuad)
-      newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
+      newElems.push_back( aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] ));
     else
-      newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
-    myLastCreatedElems.Append(newElem);
-    if ( aShapeId && newElem )
-      aMesh->SetMeshElementOnShape( newElem, aShapeId );
-} // end if(!theFace->IsQuadratic())
+      newElems.push_back( aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] ));
+
+  } // end if(!theFace->IsQuadratic())
+
   else { // theFace is quadratic
     // we have to split theFace on simple triangles and one simple quadrangle
     int tmp = il1/2;
@@ -8033,66 +9055,38 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
     //           n4           n6      n5     n4
 
     // create new elements
-    int aShapeId = FindShape( theFace );
-
     int n1,n2,n3;
-    if(nbFaceNodes==6) { // quadratic triangle
-      SMDS_MeshElement* newElem =
-        aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
-      myLastCreatedElems.Append(newElem);
-      if ( aShapeId && newElem )
-        aMesh->SetMeshElementOnShape( newElem, aShapeId );
-      if(theFace->IsMediumNode(nodes[il1])) {
+    if ( nbFaceNodes == 6 ) { // quadratic triangle
+      newElems.push_back( aMesh->AddFace( nodes[3], nodes[4], nodes[5] ));
+      if ( theFace->IsMediumNode(nodes[il1]) ) {
         // create quadrangle
-        newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
-        myLastCreatedElems.Append(newElem);
-        if ( aShapeId && newElem )
-          aMesh->SetMeshElementOnShape( newElem, aShapeId );
+        newElems.push_back( aMesh->AddFace( nodes[0], nodes[1], nodes[3], nodes[5] ));
         n1 = 1;
         n2 = 2;
         n3 = 3;
       }
       else {
         // create quadrangle
-        newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
-        myLastCreatedElems.Append(newElem);
-        if ( aShapeId && newElem )
-          aMesh->SetMeshElementOnShape( newElem, aShapeId );
+        newElems.push_back( aMesh->AddFace( nodes[1], nodes[2], nodes[3], nodes[5] ));
         n1 = 0;
         n2 = 1;
         n3 = 5;
       }
     }
     else { // nbFaceNodes==8 - quadratic quadrangle
-      SMDS_MeshElement* newElem =
-        aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
-      myLastCreatedElems.Append(newElem);
-      if ( aShapeId && newElem )
-        aMesh->SetMeshElementOnShape( newElem, aShapeId );
-      newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
-      myLastCreatedElems.Append(newElem);
-      if ( aShapeId && newElem )
-        aMesh->SetMeshElementOnShape( newElem, aShapeId );
-      newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
-      myLastCreatedElems.Append(newElem);
-      if ( aShapeId && newElem )
-        aMesh->SetMeshElementOnShape( newElem, aShapeId );
-      if(theFace->IsMediumNode(nodes[il1])) {
+      newElems.push_back( aMesh->AddFace( nodes[3], nodes[4], nodes[5] ));
+      newElems.push_back( aMesh->AddFace( nodes[5], nodes[6], nodes[7] ));
+      newElems.push_back( aMesh->AddFace( nodes[5], nodes[7], nodes[3] ));
+      if ( theFace->IsMediumNode( nodes[ il1 ])) {
         // create quadrangle
-        newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
-        myLastCreatedElems.Append(newElem);
-        if ( aShapeId && newElem )
-          aMesh->SetMeshElementOnShape( newElem, aShapeId );
+        newElems.push_back( aMesh->AddFace( nodes[0], nodes[1], nodes[3], nodes[7] ));
         n1 = 1;
         n2 = 2;
         n3 = 3;
       }
       else {
         // create quadrangle
-        newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
-        myLastCreatedElems.Append(newElem);
-        if ( aShapeId && newElem )
-          aMesh->SetMeshElementOnShape( newElem, aShapeId );
+        newElems.push_back( aMesh->AddFace( nodes[1], nodes[2], nodes[3], nodes[7] ));
         n1 = 0;
         n2 = 1;
         n3 = 7;
@@ -8100,30 +9094,34 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
     }
     // create needed triangles using n1,n2,n3 and inserted nodes
     int nbn = 2 + aNodesToInsert.size();
-    //const SMDS_MeshNode* aNodes[nbn];
     vector<const SMDS_MeshNode*> aNodes(nbn);
-    aNodes[0] = nodes[n1];
+    aNodes[0    ] = nodes[n1];
     aNodes[nbn-1] = nodes[n2];
     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
       aNodes[iNode++] = *nIt;
     }
-    for(i=1; i<nbn; i++) {
-      SMDS_MeshElement* newElem =
-        aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
-      myLastCreatedElems.Append(newElem);
-      if ( aShapeId && newElem )
-        aMesh->SetMeshElementOnShape( newElem, aShapeId );
-    }
+    for ( i = 1; i < nbn; i++ )
+      newElems.push_back( aMesh->AddFace( aNodes[i-1], aNodes[i], nodes[n3] ));
   }
-  // remove old face
+
+  // remove the old face
+  for ( size_t i = 0; i < newElems.size(); ++i )
+    if ( newElems[i] )
+    {
+      aMesh->SetMeshElementOnShape( newElems[i], theFace->getshapeId() );
+      myLastCreatedElems.Append( newElems[i] );
+    }
+  ReplaceElemInGroups( theFace, newElems, aMesh );
   aMesh->RemoveElement(theFace);
-}
+
+} // InsertNodesIntoLink()
 
 //=======================================================================
 //function : UpdateVolumes
 //purpose  :
 //=======================================================================
+
 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
                                       const SMDS_MeshNode*        theBetweenNode2,
                                       list<const SMDS_MeshNode*>& theNodesToInsert)
@@ -8185,24 +9183,16 @@ void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode
       quantities[iface] = nbFaceNodes + nbInserted;
     }
 
-    // Replace or update the volume
+    // Replace the volume
     SMESHDS_Mesh *aMesh = GetMeshDS();
 
-    if (elem->IsPoly()) {
-      aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
-
-    }
-    else {
-      int aShapeId = FindShape( elem );
-
-      SMDS_MeshElement* newElem =
-        aMesh->AddPolyhedralVolume(poly_nodes, quantities);
-      myLastCreatedElems.Append(newElem);
-      if (aShapeId && newElem)
-        aMesh->SetMeshElementOnShape(newElem, aShapeId);
-
-      aMesh->RemoveElement(elem);
+    if ( SMDS_MeshElement* newElem = aMesh->AddPolyhedralVolume( poly_nodes, quantities ))
+    {
+      aMesh->SetMeshElementOnShape( newElem, elem->getshapeId() );
+      myLastCreatedElems.Append( newElem );
+      ReplaceElemInGroups( elem, newElem, aMesh );
     }
+    aMesh->RemoveElement( elem );
   }
 }
 
@@ -8232,7 +9222,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
  */
 //=======================================================================
@@ -8303,7 +9293,7 @@ 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)
+    // remove central nodes of biquadratic elements (biquad->quad conversion)
     if ( hasCentralNodes )
       for ( size_t i = nbNodes * 2; i < nodes.size(); ++i )
         if ( nodes[i]->NbInverseElements() == 0 )
@@ -8381,6 +9371,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theT
   aHelper.SetIsQuadratic( true );
   aHelper.SetIsBiQuadratic( theToBiQuad );
   aHelper.SetElementsOnShape(true);
+  aHelper.ToFixNodeParameters( true );
 
   // convert elements assigned to sub-meshes
   int nbCheckedElems = 0;
@@ -8493,11 +9484,20 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theT
       if ( !volume ) continue;
 
       const SMDSAbs_EntityType type = volume->GetEntityType();
-      if (( theToBiQuad  && type == SMDSEntity_TriQuad_Hexa ) ||
-          ( !theToBiQuad && type == SMDSEntity_Quad_Hexa ))
+      if ( volume->IsQuadratic() )
       {
-        aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume ));
-        continue;
+        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());
@@ -8745,6 +9745,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() )
   {
@@ -8752,11 +9754,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 ))
@@ -8764,13 +9766,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 );
@@ -8921,7 +9923,6 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
-  MESSAGE ("::::SewSideElements()");
   if ( theSide1.size() != theSide2.size() )
     return SEW_DIFF_NB_OF_ELEMENTS;
 
@@ -8940,7 +9941,7 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
   //    face does not exist
 
   SMESHDS_Mesh* aMesh = GetMeshDS();
-  // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
+  // TODO algorithm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
   TIDSortedElemSet             faceSet1, faceSet2;
   set<const SMDS_MeshElement*> volSet1,  volSet2;
@@ -9361,11 +10362,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
@@ -9374,11 +10379,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++;
@@ -9390,21 +10394,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 );
           }
+        }
       }
     }
 
@@ -9586,6 +10586,70 @@ 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 = SMDSAbs_All;
+  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
@@ -9613,7 +10677,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
@@ -9633,16 +10697,17 @@ 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 )
   {
@@ -9650,22 +10715,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() )
+      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 );
       }
@@ -9676,12 +10744,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;
@@ -9692,8 +10758,8 @@ 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
+  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
 */
 //================================================================================
@@ -9701,7 +10767,6 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
                                     const std::list< int >& theListOfModifiedElems )
 {
-  MESSAGE("DoubleNodes");
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
@@ -9729,6 +10794,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 );
     }
@@ -9774,10 +10840,9 @@ bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
     if ( anElem )
-      {
-      MESSAGE("ChangeElementNodes");
+    {
       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
-      }
+    }
   }
 
   return true;
@@ -9830,15 +10895,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
     {
@@ -9849,12 +10911,14 @@ namespace {
 
 //================================================================================
 /*!
-  \brief Identify the elements that will be affected by node duplication (actual duplication is not performed.
+  \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).
+         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()
@@ -9867,44 +10931,134 @@ bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theEl
                                                    TIDSortedElemSet&       theAffectedElems)
 {
   if ( theShape.IsNull() )
-    return false;
-
-  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)));
-  }
+    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 indicated elements and get elements by back references from their nodes
-  TIDSortedElemSet::const_iterator elemItr = theElems.begin();
-  for ( ;  elemItr != theElems.end(); ++elemItr )
+    // --- iterates on elements to be replicated and get elements by back references from their nodes
+
+    TIDSortedElemSet::const_iterator elemItr = theElems.begin();
+    for ( ;  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 );
+      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++)
+      {
+        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() )
+        {
+          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() );
+          if (normal*p > 0)
+          {
+            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)
+      {
+        theAffectedElems.insert(anEdge);
+      }
+    }
+  }
+  else
   {
-    SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
-    if (!anElem)
-      continue;
+    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)));
+    }
 
-    SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
-    while ( nodeItr->more() )
+    // iterates on indicated elements and get elements by back references from their nodes
+    TIDSortedElemSet::const_iterator elemItr = theElems.begin();
+    for ( ;  elemItr != theElems.end(); ++elemItr )
     {
-      const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
-      if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
+      SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
+      if (!anElem)
         continue;
-      SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
-      while ( backElemItr->more() )
+      SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
+      while ( nodeItr->more() )
       {
-        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 );
+        const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
+        if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
+          continue;
+        SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
+        while ( backElemItr->more() )
+        {
+          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 );
+        }
       }
     }
   }
@@ -9931,16 +11085,16 @@ bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
     return false;
 
   const double aTol = Precision::Confusion();
-  auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
-  auto_ptr<_FaceClassifier>              aFaceClassifier;
+  SMESHUtils::Deleter< BRepClass3d_SolidClassifier> bsc3d;
+  SMESHUtils::Deleter<_FaceClassifier>              aFaceClassifier;
   if ( theShape.ShapeType() == TopAbs_SOLID )
   {
-    bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
+    bsc3d._obj = new BRepClass3d_SolidClassifier( theShape );
     bsc3d->PerformInfinitePoint(aTol);
   }
   else if (theShape.ShapeType() == TopAbs_FACE )
   {
-    aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
+    aFaceClassifier._obj = new _FaceClassifier( TopoDS::Face( theShape ));
   }
 
   // iterates on indicated elements and get elements by back references from their nodes
@@ -9963,7 +11117,7 @@ bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
       {
         const SMDS_MeshElement* curElem = backElemItr->next();
         if ( curElem && theElems.find(curElem) == theElems.end() &&
-             ( bsc3d.get() ?
+             ( bsc3d ?
                isInside( curElem, *bsc3d, aTol ) :
                isInside( curElem, *aFaceClassifier, aTol )))
           anAffected.insert( curElem );
@@ -9983,16 +11137,17 @@ bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
  */
 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
 {
-//  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
-//  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
-//  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
-//  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
   gp_Vec vref(p0, p1);
   gp_Vec v1(p0, g1);
   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() );
 }
 
 /*!
@@ -10005,17 +11160,20 @@ double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const
  * 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
- * @return TRUE if operation has been completed successfully, FALSE otherwise
+ * \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");
-  MESSAGE("----------------------------------------------");
+  // MESSAGE("----------------------------------------------");
+  // MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
+  // MESSAGE("----------------------------------------------");
 
   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
   meshDS->BuildDownWardConnectivity(true);
@@ -10038,83 +11196,93 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
   std::set<int> emptySet;
   emptyMap.clear();
 
-  MESSAGE(".. Number of domains :"<<theElems.size());
+  //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 < theElems.size()-1; idom++)
+  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)
     {
-//       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 ;
+      // check if the element belongs to a domain further in the list
+      for ( size_t idombis = idombisdeb; idombis < theElems.size(); idombis++ )
+      {
+        const TIDSortedElemSet& domainbis = theElems[idombis];
+        if ( domainbis.count( anElem ))
         {
-          SMDS_MeshElement* anElem = (SMDS_MeshElement*) *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 ;
-            }
-          }
+          MESSAGE(".... Domain #" << idom);
+          MESSAGE(".... Domain #" << idombis);
+          throw SALOME_Exception("The domains are not disjoint.");
+          return false ;
         }
+      }
     }
+  }
 
-  for (int idom = 0; idom < theElems.size(); idom++)
-    {
+  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 his domain.
+    // --- 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 his domain.
 
-      MESSAGE("... Neighbors of domain #" << idom);
-      const TIDSortedElemSet& domain = theElems[idom];
-      TIDSortedElemSet::const_iterator elemItr = domain.begin();
-      for (; elemItr != domain.end(); ++elemItr)
+    //MESSAGE("... Neighbors of domain #" << idom);
+    const TIDSortedElemSet& domain = theElems[idom];
+    TIDSortedElemSet::const_iterator elemItr = domain.begin();
+    for (; elemItr != domain.end(); ++elemItr)
+    {
+      const SMDS_MeshElement* anElem = *elemItr;
+      if (!anElem)
+        continue;
+      int vtkId = anElem->getVtkId();
+      //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
+      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++)
+      {
+        int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
+        const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
+        if (elem && ! domain.count(elem)) // neighbor is in another domain : face is shared
         {
-          SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
-          if (!anElem)
-            continue;
-          int vtkId = anElem->getVtkId();
-          //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
-          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++)
+          bool ok = false;
+          for ( size_t 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))
             {
-              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
-                {
-                  bool ok = false ;
-                  for (int idombis = 0; idombis < theElems.size(); 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 ) // the characteristics of the face is stored
-                  {
-                    DownIdType face(downIds[n], downTypes[n]);
-                    if (!faceDomains.count(face))
-                      faceDomains[face] = emptyMap; // create an empty entry for face
-                    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);
-                      }
-                  }
-                }
+              faceDomains[face][idom] = vtkId; // volume associated to face in this domain
+              celldom[vtkId] = idom;
+              //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
+            }
+            if ( !ok )
+            {
+              theRestDomElems.insert( elem );
+              faceDomains[face][iRestDom] = neighborsVtkIds[n];
+              celldom[neighborsVtkIds[n]] = iRestDom;
             }
+          }
         }
+      }
     }
+  }
 
   //MESSAGE("Number of shared faces " << faceDomains.size());
   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
@@ -10123,51 +11291,49 @@ 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 = (idomain == iRestDom) ? theRestDomElems : theElems[idomain];
+    itface = faceDomains.begin();
+    for (; itface != faceDomains.end(); ++itface)
     {
-      //MESSAGE("Domain " << idomain);
-      const TIDSortedElemSet& domain = theElems[idomain];
-      itface = faceDomains.begin();
-      for (; itface != faceDomains.end(); ++itface)
+      const 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);
+      std::set<int>::iterator itn = oldNodes.begin();
+      for (; itn != oldNodes.end(); ++itn)
+      {
+        int oldId = *itn;
+        //MESSAGE("     node " << oldId);
+        vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
+        for (int i=0; i<l.ncells; i++)
         {
-          std::map<int, int> domvol = itface->second;
-          if (!domvol.count(idomain))
+          int vtkId = l.cells[i];
+          const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
+          if (!domain.count(anElem))
             continue;
-          DownIdType face = itface->first;
-          //MESSAGE(" --- face " << face.cellId);
-          std::set<int> oldNodes;
-          oldNodes.clear();
-          grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
-          std::set<int>::iterator itn = oldNodes.begin();
-          for (; itn != oldNodes.end(); ++itn)
-            {
-              int oldId = *itn;
-              //MESSAGE("     node " << oldId);
-              vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
-              for (int i=0; i<l.ncells; i++)
-                {
-                  int vtkId = l.cells[i];
-                  const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
-                  if (!domain.count(anElem))
-                    continue;
-                  int vtkType = grid->GetCellType(vtkId);
-                  int downId = grid->CellIdToDownId(vtkId);
-                  if (downId < 0)
-                    {
-                      MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
-                      continue; // not OK at this stage of the algorithm:
-                                //no cells created after BuildDownWardConnectivity
-                    }
-                  DownIdType aCell(downId, vtkType);
-                  if (!cellDomains.count(aCell))
-                    cellDomains[aCell] = emptyMap; // create an empty entry for cell
-                  cellDomains[aCell][idomain] = vtkId;
-                  celldom[vtkId] = idomain;
-                  //MESSAGE("       cell " << vtkId << " domain " << idomain);
-                }
-            }
+          int vtkType = grid->GetCellType(vtkId);
+          int downId = grid->CellIdToDownId(vtkId);
+          if (downId < 0)
+          {
+            MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
+            continue; // not OK at this stage of the algorithm:
+            //no cells created after BuildDownWardConnectivity
+          }
+          DownIdType aCell(downId, vtkType);
+          cellDomains[aCell][idomain] = vtkId;
+          celldom[vtkId] = idomain;
+          //MESSAGE("       cell " << vtkId << " domain " << idomain);
         }
+      }
     }
+  }
 
   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
   //     for each shared face, get the nodes
@@ -10181,188 +11347,187 @@ 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)
 
-  MESSAGE(".. Duplication of the nodes");
-  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)
     {
-      itface = faceDomains.begin();
-      for (; itface != faceDomains.end(); ++itface)
+      const 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);
+      std::set<int>::iterator itn = oldNodes.begin();
+      for (; itn != oldNodes.end(); ++itn)
+      {
+        int oldId = *itn;
+        if (nodeDomains[oldId].empty())
         {
-          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);
-          std::set<int>::iterator itn = oldNodes.begin();
-          for (; itn != oldNodes.end(); ++itn)
+          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;
+          //MESSAGE("         domain " << idom);
+          if (!nodeDomains[oldId].count(idom)) // --- node to clone
+          {
+            if (nodeDomains[oldId].size() >= 2) // a multiple node
             {
-              int oldId = *itn;
-              //MESSAGE("-+-+-a 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
-                  //MESSAGE("-+-+-b     oldNode " << oldId << " domain " << idomain);
-                }
-              std::map<int, int>::iterator itdom = domvol.begin();
-              for (; itdom != domvol.end(); ++itdom)
-                {
-                  int idom = itdom->first;
-                  //MESSAGE("         domain " << idom);
-                  if (!nodeDomains[oldId].count(idom)) // --- node to clone
-                    {
-                      if (nodeDomains[oldId].size() >= 2) // a multiple node
-                        {
-                          vector<int> orderedDoms;
-                          //MESSAGE("multiple node " << oldId);
-                          if (mutipleNodes.count(oldId))
-                            orderedDoms = mutipleNodes[oldId];
-                          else
-                            {
-                              map<int,int>::iterator it = nodeDomains[oldId].begin();
-                              for (; it != nodeDomains[oldId].end(); ++it)
-                                orderedDoms.push_back(it->first);
-                            }
-                          orderedDoms.push_back(idom); // TODO order ==> push_front or back
-                          //stringstream txt;
-                          //for (int i=0; i<orderedDoms.size(); i++)
-                          //  txt << orderedDoms[i] << " ";
-                          //MESSAGE("orderedDoms " << txt.str());
-                          mutipleNodes[oldId] = orderedDoms;
-                        }
-                      double *coords = grid->GetPoint(oldId);
-                      SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
-                      int newId = newNode->getVtkId();
-                      nodeDomains[oldId][idom] = newId; // cloned node for other domains
-                      //MESSAGE("-+-+-c     oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
-                    }
-                }
+              vector<int> orderedDoms;
+              //MESSAGE("multiple node " << oldId);
+              if (mutipleNodes.count(oldId))
+                orderedDoms = mutipleNodes[oldId];
+              else
+              {
+                map<int,int>::iterator it = nodeDomains[oldId].begin();
+                for (; it != nodeDomains[oldId].end(); ++it)
+                  orderedDoms.push_back(it->first);
+              }
+              orderedDoms.push_back(idom); // TODO order ==> push_front or back
+              //stringstream txt;
+              //for (int i=0; i<orderedDoms.size(); i++)
+              //  txt << orderedDoms[i] << " ";
+              //MESSAGE("orderedDoms " << txt.str());
+              mutipleNodes[oldId] = orderedDoms;
             }
+            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("-+-+-c     oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
+          }
         }
+      }
     }
+  }
 
-  MESSAGE(".. Creation of elements");
-  for (int idomain = 0; idomain < theElems.size(); idomain++)
+  //MESSAGE(".. Creation of elements");
+  for (int idomain = idom0; idomain < nbDomains; idomain++)
+  {
+    itface = faceDomains.begin();
+    for (; itface != faceDomains.end(); ++itface)
     {
-      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;
+        unsigned char cellType = itface->first.cellType;
+        // --- shared edge or shared face ?
+        if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
         {
-          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
+          int nodes[3];
+          int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
+          for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
+            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);
+          const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
+          const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
+          for (int ie =0; ie < nbEdges; ie++)
+          {
+            int nodes[3];
+            int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
+            if ( mutipleNodes.count(nodes[0]) && mutipleNodes.count( nodes[ nbNodes-1 ]))
             {
-              //MESSAGE("multiple Nodes detected on a shared face");
-              int downId = itface->first.cellId;
-              unsigned char cellType = itface->first.cellType;
-              // --- shared edge or shared face ?
-              if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
-                {
-                  int nodes[3];
-                  int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
-                  for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
-                    if (mutipleNodes.count(nodes[i]))
-                      if (!mutipleNodesToFace.count(nodes[i]))
-                        mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
-                }
-              else // shared face (between two volumes)
+              vector<int> vn0 = mutipleNodes[nodes[0]];
+              vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
+              vector<int> doms;
+              for ( size_t i0 = 0; i0 < vn0.size(); i0++ )
+                for ( size_t 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]);
+                gp_Pnt p0(coords[0], coords[1], coords[2]);
+                coords = grid->GetPoint(nodes[nbNodes - 1]);
+                gp_Pnt p1(coords[0], coords[1], coords[2]);
+                gp_Pnt gref;
+                int vtkVolIds[1000];  // an edge can belong to a lot of volumes
+                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 ( size_t id = 0; id < doms.size(); id++ )
                 {
-                  int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
-                  const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
-                  const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
-                  for (int ie =0; ie < nbEdges; ie++)
+                  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 (domain.count(elem))
                     {
-                      int nodes[3];
-                      int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
-                      if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
-                        {
-                          vector<int> vn0 = mutipleNodes[nodes[0]];
-                          vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
-                          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]);
-                              gp_Pnt p0(coords[0], coords[1], coords[2]);
-                              coords = grid->GetPoint(nodes[nbNodes - 1]);
-                              gp_Pnt p1(coords[0], coords[1], coords[2]);
-                              gp_Pnt gref;
-                              int vtkVolIds[1000];  // an edge can belong to a lot of volumes
-                              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 < doms.size(); id++)
-                                {
-                                  int idom = doms[id];
-                                  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))
-                                        {
-                                          SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
-                                          domvol[idom] = svol;
-                                          //MESSAGE("  domain " << idom << " volume " << elem->GetID());
-                                          double values[3];
-                                          vtkIdType npts = 0;
-                                          vtkIdType* pts = 0;
-                                          grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
-                                          SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
-                                          if (id ==0)
-                                            {
-                                              gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
-                                              angleDom[idom] = 0;
-                                            }
-                                          else
-                                            {
-                                              gp_Pnt g(values[0], values[1], values[2]);
-                                              angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
-                                              //MESSAGE("  angle=" << angleDom[idom]);
-                                            }
-                                          break;
-                                        }
-                                    }
-                                }
-                              map<double, int> sortedDom; // sort domains by angle
-                              for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
-                                sortedDom[ia->second] = ia->first;
-                              vector<int> vnodes;
-                              vector<int> vdom;
-                              for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
-                                {
-                                  vdom.push_back(ib->second);
-                                  //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
-                                }
-                              for (int ino = 0; ino < nbNodes; ino++)
-                                vnodes.push_back(nodes[ino]);
-                              edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
-                            }
-                        }
+                      SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
+                      domvol[idom] = svol;
+                      //MESSAGE("  domain " << idom << " volume " << elem->GetID());
+                      double values[3];
+                      vtkIdType npts = 0;
+                      vtkIdType* pts = 0;
+                      grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
+                      SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
+                      if (id ==0)
+                      {
+                        gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
+                        angleDom[idom] = 0;
+                      }
+                      else
+                      {
+                        gp_Pnt g(values[0], values[1], values[2]);
+                        angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
+                        //MESSAGE("  angle=" << angleDom[idom]);
+                      }
+                      break;
                     }
+                  }
+                }
+                map<double, int> sortedDom; // sort domains by angle
+                for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
+                  sortedDom[ia->second] = ia->first;
+                vector<int> vnodes;
+                vector<int> vdom;
+                for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
+                {
+                  vdom.push_back(ib->second);
+                  //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
                 }
+                for (int ino = 0; ino < nbNodes; ino++)
+                  vnodes.push_back(nodes[ino]);
+                edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
+              }
             }
+          }
         }
+      }
     }
+  }
 
   // --- iterate on shared faces (volumes to modify, face to extrude)
   //     get node id's of the face (id SMDS = id VTK)
@@ -10374,119 +11539,119 @@ 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");
+  //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)
     {
-      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)
-        {
-          DownIdType face = itface->first;
-          std::set<int> oldNodes;
-          std::set<int>::iterator itn;
-          oldNodes.clear();
-          grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
-
-          std::map<int, int> domvol = itface->second;
-          std::map<int, int>::iterator itdom = domvol.begin();
-          int dom1 = itdom->first;
-          int vtkVolId = itdom->second;
-          itdom++;
-          int dom2 = itdom->first;
-          SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
-                                                             nodeQuadDomains);
-          stringstream grpname;
-          grpname << "j_";
-          if (dom1 < dom2)
-            grpname << dom1 << "_" << dom2;
-          else
-            grpname << dom2 << "_" << dom1;
-          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());
-        }
+      DownIdType face = itface->first;
+      std::set<int> oldNodes;
+      std::set<int>::iterator itn;
+      oldNodes.clear();
+      grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
+
+      std::map<int, int> domvol = itface->second;
+      std::map<int, int>::iterator itdom = domvol.begin();
+      int dom1 = itdom->first;
+      int vtkVolId = itdom->second;
+      itdom++;
+      int dom2 = itdom->first;
+      SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
+                                                       nodeQuadDomains);
+      stringstream grpname;
+      grpname << "j_";
+      if (dom1 < dom2)
+        grpname << dom1 << "_" << dom2;
+      else
+        grpname << dom2 << "_" << dom1;
+      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());
     }
+  }
 
   // --- create volumes on multiple domain intersection if requested
   //     iterate on mutipleNodesToFace
   //     iterate on edgesMultiDomains
 
-  MESSAGE(".. Creation of elements: multiple junction");
+  //MESSAGE(".. Creation of elements: multiple junction");
   if (createJointElems)
+  {
+    // --- iterate on mutipleNodesToFace
+
+    std::map<int, std::vector<int> >::iterator itn =  mutipleNodesToFace.begin();
+    for (; itn != mutipleNodesToFace.end(); ++itn)
     {
-      // --- iterate on mutipleNodesToFace
+      int node = itn->first;
+      vector<int> orderDom = itn->second;
+      vector<vtkIdType> orderedNodes;
+      for ( size_t idom = 0; idom < orderDom.size(); idom++ )
+        orderedNodes.push_back( nodeDomains[ node ][ orderDom[ idom ]]);
+      SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
+
+      stringstream grpname;
+      grpname << "m2j_";
+      grpname << 0 << "_" << 0;
+      int idg;
+      string namegrp = grpname.str();
+      if (!mapOfJunctionGroups.count(namegrp))
+        mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
+      SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
+      if (sgrp)
+        sgrp->Add(face->GetID());
+    }
 
-      std::map<int, std::vector<int> >::iterator itn =  mutipleNodesToFace.begin();
-      for (; itn != mutipleNodesToFace.end(); ++itn)
-        {
-          int node = itn->first;
-          vector<int> orderDom = itn->second;
-          vector<vtkIdType> orderedNodes;
-          for (int idom = 0; idom <orderDom.size(); idom++)
-            orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
-            SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
-
-            stringstream grpname;
-            grpname << "m2j_";
-            grpname << 0 << "_" << 0;
-            int idg;
-            string namegrp = grpname.str();
-            if (!mapOfJunctionGroups.count(namegrp))
-              mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
-            SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
-            if (sgrp)
-              sgrp->Add(face->GetID());
-        }
-
-      // --- iterate on edgesMultiDomains
-
-      std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
-      for (; ite != edgesMultiDomains.end(); ++ite)
-        {
-          vector<int> nodes = ite->first;
-          vector<int> orderDom = ite->second;
-          vector<vtkIdType> orderedNodes;
-          if (nodes.size() == 2)
-            {
-              //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
-              for (int ino=0; ino < nodes.size(); ino++)
-                if (orderDom.size() == 3)
-                  for (int idom = 0; idom <orderDom.size(); idom++)
-                    orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
-                else
-                  for (int idom = orderDom.size()-1; idom >=0; idom--)
-                    orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
-              SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
-
-              int idg;
-              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());
-              if (sgrp)
-                sgrp->Add(vol->GetID());
-            }
+    // --- iterate on edgesMultiDomains
+
+    std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
+    for (; ite != edgesMultiDomains.end(); ++ite)
+    {
+      vector<int> nodes = ite->first;
+      vector<int> orderDom = ite->second;
+      vector<vtkIdType> orderedNodes;
+      if (nodes.size() == 2)
+      {
+        //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
+        for ( size_t ino = 0; ino < nodes.size(); ino++ )
+          if ( orderDom.size() == 3 )
+            for ( size_t idom = 0; idom < orderDom.size(); idom++ )
+              orderedNodes.push_back( nodeDomains[ nodes[ ino ]][ orderDom[ idom ]]);
           else
-            {
-              INFOS("Quadratic multiple joints not implemented");
-              // TODO quadratic nodes
-            }
-        }
+            for (int idom = orderDom.size()-1; idom >=0; idom--)
+              orderedNodes.push_back( nodeDomains[ nodes[ ino ]][ orderDom[ idom ]]);
+        SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
+
+        int idg;
+        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());
+        if (sgrp)
+          sgrp->Add(vol->GetID());
+      }
+      else
+      {
+        //INFOS("Quadratic multiple joints not implemented");
+        // TODO quadratic nodes
+      }
     }
+  }
 
   // --- list the explicit faces and edges of the mesh that need to be modified,
   //     i.e. faces and edges built with one or more duplicated nodes.
@@ -10498,38 +11663,38 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
   faceOrEdgeDom.clear();
   feDom.clear();
 
-  MESSAGE(".. Modification of elements");
-  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)
     {
-      std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
-      for (; itnod != nodeDomains.end(); ++itnod)
-        {
-          int oldId = itnod->first;
-          //MESSAGE("     node " << oldId);
-          vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
-          for (int i = 0; i < l.ncells; i++)
+      int oldId = itnod->first;
+      //MESSAGE("     node " << oldId);
+      vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
+      for (int i = 0; i < l.ncells; i++)
+      {
+        int vtkId = l.cells[i];
+        int vtkType = grid->GetCellType(vtkId);
+        int downId = grid->CellIdToDownId(vtkId);
+        if (downId < 0)
+          continue; // new cells: not to be modified
+        DownIdType aCell(downId, vtkType);
+        int volParents[1000];
+        int nbvol = grid->GetParentVolumes(volParents, vtkId);
+        for (int j = 0; j < nbvol; j++)
+          if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
+            if (!feDom.count(vtkId))
             {
-              int vtkId = l.cells[i];
-              int vtkType = grid->GetCellType(vtkId);
-              int downId = grid->CellIdToDownId(vtkId);
-              if (downId < 0)
-                continue; // new cells: not to be modified
-              DownIdType aCell(downId, vtkType);
-              int volParents[1000];
-              int nbvol = grid->GetParentVolumes(volParents, vtkId);
-              for (int j = 0; j < nbvol; j++)
-                if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
-                  if (!feDom.count(vtkId))
-                    {
-                      feDom[vtkId] = idomain;
-                      faceOrEdgeDom[aCell] = emptyMap;
-                      faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
-                      //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
-                      //        << " type " << vtkType << " downId " << downId);
-                    }
+              feDom[vtkId] = idomain;
+              faceOrEdgeDom[aCell] = emptyMap;
+              faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
+              //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
+              //        << " type " << vtkType << " downId " << downId);
             }
-        }
+      }
     }
+  }
 
   // --- iterate on shared faces (volumes to modify, face to extrude)
   //     get node id's of the face
@@ -10537,43 +11702,51 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
 
   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
   for (int m=0; m<3; m++)
+  {
+    std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
+    itface = (*amap).begin();
+    for (; itface != (*amap).end(); ++itface)
     {
-      std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
-      itface = (*amap).begin();
-      for (; itface != (*amap).end(); ++itface)
+      DownIdType face = itface->first;
+      std::set<int> oldNodes;
+      std::set<int>::iterator itn;
+      oldNodes.clear();
+      grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
+      //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
+      std::map<int, int> localClonedNodeIds;
+
+      std::map<int, int> domvol = itface->second;
+      std::map<int, int>::iterator itdom = domvol.begin();
+      for (; itdom != domvol.end(); ++itdom)
+      {
+        int idom = itdom->first;
+        int vtkVolId = itdom->second;
+        //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
+        localClonedNodeIds.clear();
+        for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
         {
-          DownIdType face = itface->first;
-          std::set<int> oldNodes;
-          std::set<int>::iterator itn;
-          oldNodes.clear();
-          grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
-          //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
-          std::map<int, int> localClonedNodeIds;
-
-          std::map<int, int> domvol = itface->second;
-          std::map<int, int>::iterator itdom = domvol.begin();
-          for (; itdom != domvol.end(); ++itdom)
-            {
-              int idom = itdom->first;
-              int vtkVolId = itdom->second;
-              //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
-              localClonedNodeIds.clear();
-              for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
-                {
-                  int oldId = *itn;
-                  if (nodeDomains[oldId].count(idom))
-                    {
-                      localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
-                      //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
-                    }
-                }
-              meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
-            }
+          int oldId = *itn;
+          if (nodeDomains[oldId].count(idom))
+          {
+            localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
+            //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
+          }
         }
+        meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
+      }
     }
+  }
+
+  // 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();
+  grid->DeleteLinks();
 
   CHRONOSTOP(50);
   counters::stats();
@@ -10592,9 +11765,9 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
  */
 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
 {
-  MESSAGE("-------------------------------------------------");
-  MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
-  MESSAGE("-------------------------------------------------");
+  // MESSAGE("-------------------------------------------------");
+  // MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
+  // MESSAGE("-------------------------------------------------");
 
   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
 
@@ -10609,135 +11782,137 @@ bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSort
   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
   mapOfJunctionGroups.clear();
 
-  for (int idom = 0; idom < theElems.size(); idom++)
+  for ( size_t idom = 0; idom < theElems.size(); idom++ )
+  {
+    const TIDSortedElemSet&           domain = theElems[idom];
+    TIDSortedElemSet::const_iterator elemItr = domain.begin();
+    for ( ; elemItr != domain.end(); ++elemItr )
     {
-      const TIDSortedElemSet& domain = theElems[idom];
-      TIDSortedElemSet::const_iterator elemItr = domain.begin();
-      for (; elemItr != domain.end(); ++elemItr)
-        {
-          SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
-          SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
-          if (!aFace)
-            continue;
-          // MESSAGE("aFace=" << aFace->GetID());
-          bool isQuad = aFace->IsQuadratic();
-          vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
-
-          // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
-
-          SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
-          while (nodeIt->more())
-            {
-              const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
-              bool isMedium = isQuad && (aFace->IsMediumNode(node));
-              if (isMedium)
-                ln2.push_back(node);
-              else
-                ln0.push_back(node);
+      SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
+      SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
+      if (!aFace)
+        continue;
+      // MESSAGE("aFace=" << aFace->GetID());
+      bool isQuad = aFace->IsQuadratic();
+      vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
 
-              const SMDS_MeshNode* clone = 0;
-              if (!clonedNodes.count(node))
-                {
-                  clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
-                  clonedNodes[node] = clone;
-                }
-              else
-                clone = clonedNodes[node];
+      // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
 
-              if (isMedium)
-                ln3.push_back(clone);
-              else
-                ln1.push_back(clone);
+      SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
+      while (nodeIt->more())
+      {
+        const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
+        bool isMedium = isQuad && (aFace->IsMediumNode(node));
+        if (isMedium)
+          ln2.push_back(node);
+        else
+          ln0.push_back(node);
 
-              const SMDS_MeshNode* inter = 0;
-              if (isQuad && (!isMedium))
-                {
-                  if (!intermediateNodes.count(node))
-                    {
-                      inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
-                      intermediateNodes[node] = inter;
-                    }
-                  else
-                    inter = intermediateNodes[node];
-                  ln4.push_back(inter);
-                }
-            }
+        const SMDS_MeshNode* clone = 0;
+        if (!clonedNodes.count(node))
+        {
+          clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
+          copyPosition( node, clone );
+          clonedNodes[node] = clone;
+        }
+        else
+          clone = clonedNodes[node];
 
-          // --- extrude the face
+        if (isMedium)
+          ln3.push_back(clone);
+        else
+          ln1.push_back(clone);
 
-          vector<const SMDS_MeshNode*> ln;
-          SMDS_MeshVolume* vol = 0;
-          vtkIdType aType = aFace->GetVtkType();
-          switch (aType)
+        const SMDS_MeshNode* inter = 0;
+        if (isQuad && (!isMedium))
+        {
+          if (!intermediateNodes.count(node))
           {
-            case VTK_TRIANGLE:
-              vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
-              // MESSAGE("vol prism " << vol->GetID());
-              ln.push_back(ln1[0]);
-              ln.push_back(ln1[1]);
-              ln.push_back(ln1[2]);
-              break;
-            case VTK_QUAD:
-              vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
-              // MESSAGE("vol hexa " << vol->GetID());
-              ln.push_back(ln1[0]);
-              ln.push_back(ln1[1]);
-              ln.push_back(ln1[2]);
-              ln.push_back(ln1[3]);
-              break;
-            case VTK_QUADRATIC_TRIANGLE:
-              vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
-                                      ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
-              // MESSAGE("vol quad prism " << vol->GetID());
-              ln.push_back(ln1[0]);
-              ln.push_back(ln1[1]);
-              ln.push_back(ln1[2]);
-              ln.push_back(ln3[0]);
-              ln.push_back(ln3[1]);
-              ln.push_back(ln3[2]);
-              break;
-            case VTK_QUADRATIC_QUAD:
-//              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
-//                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
-//                                      ln4[0], ln4[1], ln4[2], ln4[3]);
-              vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
-                                      ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
-                                      ln4[0], ln4[1], ln4[2], ln4[3]);
-              // MESSAGE("vol quad hexa " << vol->GetID());
-              ln.push_back(ln1[0]);
-              ln.push_back(ln1[1]);
-              ln.push_back(ln1[2]);
-              ln.push_back(ln1[3]);
-              ln.push_back(ln3[0]);
-              ln.push_back(ln3[1]);
-              ln.push_back(ln3[2]);
-              ln.push_back(ln3[3]);
-              break;
-            case VTK_POLYGON:
-              break;
-            default:
-              break;
+            inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
+            copyPosition( node, inter );
+            intermediateNodes[node] = inter;
           }
+          else
+            inter = intermediateNodes[node];
+          ln4.push_back(inter);
+        }
+      }
 
-          if (vol)
-            {
-              stringstream grpname;
-              grpname << "jf_";
-              grpname << idom;
-              int idg;
-              string namegrp = grpname.str();
-              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());
-              if (sgrp)
-                sgrp->Add(vol->GetID());
-            }
+      // --- extrude the face
+
+      vector<const SMDS_MeshNode*> ln;
+      SMDS_MeshVolume* vol = 0;
+      vtkIdType aType = aFace->GetVtkType();
+      switch (aType)
+      {
+      case VTK_TRIANGLE:
+        vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
+        // MESSAGE("vol prism " << vol->GetID());
+        ln.push_back(ln1[0]);
+        ln.push_back(ln1[1]);
+        ln.push_back(ln1[2]);
+        break;
+      case VTK_QUAD:
+        vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
+        // MESSAGE("vol hexa " << vol->GetID());
+        ln.push_back(ln1[0]);
+        ln.push_back(ln1[1]);
+        ln.push_back(ln1[2]);
+        ln.push_back(ln1[3]);
+        break;
+      case VTK_QUADRATIC_TRIANGLE:
+        vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
+                                ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
+        // MESSAGE("vol quad prism " << vol->GetID());
+        ln.push_back(ln1[0]);
+        ln.push_back(ln1[1]);
+        ln.push_back(ln1[2]);
+        ln.push_back(ln3[0]);
+        ln.push_back(ln3[1]);
+        ln.push_back(ln3[2]);
+        break;
+      case VTK_QUADRATIC_QUAD:
+        //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
+        //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
+        //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
+        vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
+                                ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
+                                ln4[0], ln4[1], ln4[2], ln4[3]);
+        // MESSAGE("vol quad hexa " << vol->GetID());
+        ln.push_back(ln1[0]);
+        ln.push_back(ln1[1]);
+        ln.push_back(ln1[2]);
+        ln.push_back(ln1[3]);
+        ln.push_back(ln3[0]);
+        ln.push_back(ln3[1]);
+        ln.push_back(ln3[2]);
+        ln.push_back(ln3[3]);
+        break;
+      case VTK_POLYGON:
+        break;
+      default:
+        break;
+      }
+
+      if (vol)
+      {
+        stringstream grpname;
+        grpname << "jf_";
+        grpname << idom;
+        int idg;
+        string namegrp = grpname.str();
+        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());
+        if (sgrp)
+          sgrp->Add(vol->GetID());
+      }
 
-          // --- modify the face
+      // --- modify the face
 
-          aFace->ChangeNodes(&ln[0], ln.size());
-        }
+      aFace->ChangeNodes(&ln[0], ln.size());
     }
+  }
   return true;
 }
 
@@ -10747,16 +11922,16 @@ bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSort
  *  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,
+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("--------------------------------");
+  // 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,
@@ -10769,28 +11944,28 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius,
   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;
-      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 (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
@@ -10803,10 +11978,10 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius,
   grpvName += "_vol";
   SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
   if (!grp)
-    {
-      MESSAGE("group not created " << grpvName);
-      return;
-    }
+  {
+    MESSAGE("group not created " << grpvName);
+    return;
+  }
   SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
 
   int idgs; // --- group of SMDS faces on the skin
@@ -10814,10 +11989,10 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius,
   grpsName += "_skin";
   SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
   if (!grps)
-    {
-      MESSAGE("group not created " << grpsName);
-      return;
-    }
+  {
+    MESSAGE("group not created " << grpsName);
+    return;
+  }
   SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
 
   int idgi; // --- group of SMDS faces internal (several shapes)
@@ -10825,10 +12000,10 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius,
   grpiName += "_internalFaces";
   SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
   if (!grpi)
-    {
-      MESSAGE("group not created " << grpiName);
-      return;
-    }
+  {
+    MESSAGE("group not created " << grpiName);
+    return;
+  }
   SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
 
   int idgei; // --- group of SMDS faces internal (several shapes)
@@ -10836,10 +12011,10 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius,
   grpeiName += "_internalEdges";
   SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
   if (!grpei)
-    {
-      MESSAGE("group not created " << grpeiName);
-      return;
-    }
+  {
+    MESSAGE("group not created " << grpeiName);
+    return;
+  }
   SMESHDS_Group *sgrpei = dynamic_cast<SMESHDS_Group*>(grpei->GetGroupDS());
 
   // --- build downward connectivity
@@ -10857,156 +12032,154 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius,
   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() )
     {
-      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());
-            }
-        }
+      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");
+    size_t i = 0;
+    int k = 0;
+    while ( i < nodesCoords.size()-2 )
     {
-      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());
-        }
+      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;
+  {
+    //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());
-        }
+    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);
+  {
+    const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
+    //MESSAGE("startNode->nodeId " << nodeId);
 
-      double radius2 = radius*radius;
-      MESSAGE("radius2 " << radius2);
+    double radius2 = radius*radius;
+    //MESSAGE("radius2 " << radius2);
 
-      // --- volumes on start node
+    // --- 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;
-        }
+    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
+    // --- 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::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
         {
-          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 *coords = grid->GetPoint(pts[i]);
+          gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
+          distance2 = 1.E40;
+          for ( size_t j = 0; j < gpnts.size(); j++ )
+          {
+            double d2 = aPoint.SquareDistance( gpnts[ j ]);
+            if (d2 < distance2)
             {
-              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]);
-                }
+              distance2 = d2;
               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));
+                break;
             }
-          setOfVolToCheck.erase(vtkId);
+          }
+          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
@@ -11014,52 +12187,52 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius,
   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)
     {
-      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())
+      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)
         {
-          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);
+          //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)
@@ -11070,50 +12243,50 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius,
   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 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
         {
-          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));
-            }
+          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
@@ -11126,17 +12299,17 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius,
 
   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))
     {
-      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);
+      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;
@@ -11144,124 +12317,124 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius,
 
   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;
+  {
+    int shapeId = itShape->first;
+    //MESSAGE(" --- Shape ID --- "<< shapeId);
+    shapeIdToEdges[shapeId] = emptyEdges;
 
-      std::vector<int> nodesEdges;
+    std::vector<int> nodesEdges;
 
-      std::set<int>::iterator its = itShape->second.begin();
-      for (; its != itShape->second.end(); ++its)
+    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
         {
-          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);
-                    }
-                }
-            }
+          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)
+    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 < (int)nodesEdges.size(); i++ )
+          if (nodesEdges[i] == nodeTofind)
+            break;
+        if ( i == (int) nodesEdges.size() )
+          found = false; // no follower found on back
+        else
         {
-          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)
+          if (i%2) // odd ==> use the previous one
+            if (nodesEdges[i-1] < 0)
+              found = false;
+            else
             {
-              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;
-                  }
+              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;
             }
         }
-
-
-      std::vector<int> nodes;
-      nodes.push_back(shapeId);
-      std::list<int>::iterator itl = order.begin();
-      for (; itl != order.end(); itl++)
+        if (found)
+          continue;
+        // try to push front
+        found = true;
+        nodeTofind = order.front(); // try to push front
+        for ( i = 0;  i < (int)nodesEdges.size(); i++ )
+          if ( nodesEdges[i] == nodeTofind )
+            break;
+        if ( i == (int)nodesEdges.size() )
         {
-          nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
-          MESSAGE("              ordered node " << nodes[nodes.size()-1]);
+          found = false; // no predecessor found on front
+          continue;
         }
-      listOfListOfNodes.push_back(nodes);
+        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)
@@ -11285,7 +12458,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())
@@ -11293,8 +12467,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))
@@ -11306,22 +12480,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
@@ -11383,9 +12562,16 @@ 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 ), elemToCopy;
+
+  vector<const SMDS_MeshElement*> presentBndElems;
+  vector<TConnectivity>           missingBndElems;
+  vector<int>                     freeFacets;
+  TConnectivity nodes, elemNodes;
 
   SMDS_ElemIteratorPtr eIt;
   if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
@@ -11395,33 +12581,40 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
   {
     const SMDS_MeshElement* elem = eIt->next();
     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, elemNodes;
+    presentBndElems.clear();
+    missingBndElems.clear();
+    freeFacets.clear(); nodes.clear(); elemNodes.clear();
     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
     {
-      vTool.SetExternalNormal();
       const SMDS_MeshElement* otherVol = 0;
       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
       {
         if ( !vTool.IsFreeFace(iface, &otherVol) &&
              ( !aroundElements || elements.count( otherVol )))
           continue;
+        freeFacets.push_back( iface );
+      }
+      if ( missType == SMDSAbs_Face )
+        vTool.SetExternalNormal();
+      for ( size_t i = 0; i < freeFacets.size(); ++i )
+      {
+        int                iface = freeFacets[i];
         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
-        const int    nbFaceNodes = vTool.NbFaceNodes (iface);
+        const size_t nbFaceNodes = vTool.NbFaceNodes (iface);
         if ( missType == SMDSAbs_Edge ) // boundary edges
         {
           nodes.resize( 2+iQuad );
-          for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
+          for ( size_t i = 0; i < nbFaceNodes; i += 1+iQuad )
           {
-            for ( int j = 0; j < nodes.size(); ++j )
-              nodes[j] =nn[i+j];
+            for ( size_t j = 0; j < nodes.size(); ++j )
+              nodes[ j ] = nn[ i+j ];
             if ( const SMDS_MeshElement* edge =
-                 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
+                 aMesh->FindElement( nodes, SMDSAbs_Edge, /*noMedium=*/false ))
               presentBndElems.push_back( edge );
             else
               missingBndElems.push_back( nodes );
@@ -11492,37 +12685,37 @@ 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
-      for ( int i = 0; i < missingBndElems.size(); ++i )
+      for ( size_t i = 0; i < missingBndElems.size(); ++i )
       {
-        TConnectivity& nodes = missingBndElems[i];
+        TConnectivity& nodes = missingBndElems[ i ];
         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
                                                                    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 =
@@ -11542,7 +12735,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 );
         }
       }
 
@@ -11550,18 +12743,18 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
     // 3. Copy present boundary elements
     // ----------------------------------
     if ( toCopyExistingBoundary )
-      for ( int i = 0 ; i < presentBndElems.size(); ++i )
+      for ( size_t i = 0 ; i < presentBndElems.size(); ++i )
       {
         const SMDS_MeshElement* e = presentBndElems[i];
-        TConnectivity nodes( e->NbNodes() );
-        for ( inode = 0; inode < nodes.size(); ++inode )
-          nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
-        presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
+        tgtNodes.resize( e->NbNodes() );
+        for ( inode = 0; inode < tgtNodes.size(); ++inode )
+          tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
+        presentEditor->AddElement( tgtNodes, elemToCopy.Init( e ));
       }
     else // store present elements to add them to a group
-      for ( int i = 0 ; i < presentBndElems.size(); ++i )
+      for ( size_t i = 0 ; i < presentBndElems.size(); ++i )
       {
-        presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
+        presentEditor->myLastCreatedElems.Append( presentBndElems[ i ]);
       }
 
   } // loop on given elements
@@ -11588,13 +12781,55 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& 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, elemToCopy.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:;
+  }
+}