Salome HOME
Merge from V6_3_BR 15/07/2011
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
index f26db9a0cbe68c21c6d7f6ac02667a37449a2fc2..76432855fe476d48e366cff1bc5fa5211dad0628 100644 (file)
@@ -1,23 +1,23 @@
-//  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2011  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
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
 //
-//  This library is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU Lesser General Public
-//  License as published by the Free Software Foundation; either
-//  version 2.1 of the License.
+// 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.
 //
-//  This library is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-//  Lesser General Public License for more details.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
 //
-//  You should have received a copy of the GNU Lesser General Public
-//  License along with this library; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 //
-//  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
@@ -25,6 +25,7 @@
 // Created   : Mon Apr 12 16:10:22 2004
 // Author    : Edward AGAPOV (eap)
 //
+#define CHRONODEF
 #include "SMESH_MeshEditor.hxx"
 
 #include "SMDS_FaceOfNodes.hxx"
 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
 #include "SMDS_FacePosition.hxx"
 #include "SMDS_SpacePosition.hxx"
-#include "SMDS_QuadraticFaceOfNodes.hxx"
+//#include "SMDS_QuadraticFaceOfNodes.hxx"
 #include "SMDS_MeshGroup.hxx"
+#include "SMDS_LinearEdge.hxx"
+#include "SMDS_Downward.hxx"
 #include "SMDS_SetIterator.hxx"
 
 #include "SMESHDS_Group.hxx"
@@ -91,6 +94,8 @@
 #include <set>
 #include <numeric>
 #include <limits>
+#include <algorithm>
+#include <sstream>
 
 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
 
@@ -124,103 +129,130 @@ SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
                              const bool                           isPoly,
                              const int                            ID)
 {
+  //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
   SMDS_MeshElement* e = 0;
   int nbnode = node.size();
   SMESHDS_Mesh* mesh = GetMeshDS();
   switch ( type ) {
-  case SMDSAbs_0DElement:
-    if ( nbnode == 1 )
-      if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
-      else      e = mesh->Add0DElement      (node[0] );
-    break;
-  case SMDSAbs_Edge:
-    if ( nbnode == 2 )
-      if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
-      else      e = mesh->AddEdge      (node[0], node[1] );
-    else if ( nbnode == 3 )
-      if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
-      else      e = mesh->AddEdge      (node[0], node[1], node[2] );
-    break;
   case SMDSAbs_Face:
     if ( !isPoly ) {
-      if      (nbnode == 3)
-        if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
-        else      e = mesh->AddFace      (node[0], node[1], node[2] );
-      else if (nbnode == 4) 
-        if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
-        else      e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
-      else if (nbnode == 6)
-        if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
-                                          node[4], node[5], ID);
-        else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
-                                          node[4], node[5] );
-      else if (nbnode == 8)
-        if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
-                                          node[4], node[5], node[6], node[7], ID);
-        else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
-                                          node[4], node[5], node[6], node[7] );
+      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] );
+      }
+      else if (nbnode == 4) {
+        if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
+        else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
+      }
+      else if (nbnode == 6) {
+        if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
+                                               node[4], node[5], ID);
+        else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
+                                               node[4], node[5] );
+      }
+      else if (nbnode == 8) {
+        if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
+                                               node[4], node[5], node[6], node[7], ID);
+        else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
+                                               node[4], node[5], node[6], node[7] );
+      }
     } else {
-      if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
-      else      e = mesh->AddPolygonalFace      (node    );
+      if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
+      else           e = mesh->AddPolygonalFace      (node    );
     }
     break;
+
   case SMDSAbs_Volume:
     if ( !isPoly ) {
-      if      (nbnode == 4)
-        if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
-        else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
-      else if (nbnode == 5)
-        if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
-                                            node[4], ID);
-        else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
-                                            node[4] );
-      else if (nbnode == 6)
-        if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
-                                            node[4], node[5], ID);
-        else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
-                                            node[4], node[5] );
-      else if (nbnode == 8)
-        if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
-                                            node[4], node[5], node[6], node[7], ID);
-        else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
-                                            node[4], node[5], node[6], node[7] );
-      else if (nbnode == 10)
-        if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
-                                            node[4], node[5], node[6], node[7],
-                                            node[8], node[9], ID);
-        else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
-                                            node[4], node[5], node[6], node[7],
-                                            node[8], node[9] );
-      else if (nbnode == 13)
-        if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
-                                            node[4], node[5], node[6], node[7],
-                                            node[8], node[9], node[10],node[11],
-                                            node[12],ID);
-        else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
-                                            node[4], node[5], node[6], node[7],
-                                            node[8], node[9], node[10],node[11],
-                                            node[12] );
-      else if (nbnode == 15)
-        if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
-                                            node[4], node[5], node[6], node[7],
-                                            node[8], node[9], node[10],node[11],
-                                            node[12],node[13],node[14],ID);
-        else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
-                                            node[4], node[5], node[6], node[7],
-                                            node[8], node[9], node[10],node[11],
-                                            node[12],node[13],node[14] );
-      else if (nbnode == 20)
-        if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
-                                            node[4], node[5], node[6], node[7],
-                                            node[8], node[9], node[10],node[11],
-                                            node[12],node[13],node[14],node[15],
-                                            node[16],node[17],node[18],node[19],ID);
-        else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
-                                            node[4], node[5], node[6], node[7],
-                                            node[8], node[9], node[10],node[11],
-                                            node[12],node[13],node[14],node[15],
-                                            node[16],node[17],node[18],node[19] );
+      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] );
+      }
+      else if (nbnode == 5) {
+        if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+                                                 node[4], ID);
+        else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
+                                                 node[4] );
+      }
+      else if (nbnode == 6) {
+        if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], ID);
+        else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
+                                                 node[4], node[5] );
+      }
+      else if (nbnode == 8) {
+        if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], node[6], node[7], ID);
+        else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], node[6], node[7] );
+      }
+      else if (nbnode == 10) {
+        if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], node[6], node[7],
+                                                 node[8], node[9], ID);
+        else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], node[6], node[7],
+                                                 node[8], node[9] );
+      }
+      else if (nbnode == 13) {
+        if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], node[6], node[7],
+                                                 node[8], node[9], node[10],node[11],
+                                                 node[12],ID);
+        else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], node[6], node[7],
+                                                 node[8], node[9], node[10],node[11],
+                                                 node[12] );
+      }
+      else if (nbnode == 15) {
+        if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], node[6], node[7],
+                                                 node[8], node[9], node[10],node[11],
+                                                 node[12],node[13],node[14],ID);
+        else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], node[6], node[7],
+                                                 node[8], node[9], node[10],node[11],
+                                                 node[12],node[13],node[14] );
+      }
+      else if (nbnode == 20) {
+        if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], node[6], node[7],
+                                                 node[8], node[9], node[10],node[11],
+                                                 node[12],node[13],node[14],node[15],
+                                                 node[16],node[17],node[18],node[19],ID);
+        else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], node[6], node[7],
+                                                 node[8], node[9], node[10],node[11],
+                                                 node[12],node[13],node[14],node[15],
+                                                 node[16],node[17],node[18],node[19] );
+      }
+    }
+    break;
+
+  case SMDSAbs_Edge:
+    if ( nbnode == 2 ) {
+      if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
+      else           e = mesh->AddEdge      (node[0], node[1] );
+    }
+    else if ( nbnode == 3 ) {
+      if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
+      else           e = mesh->AddEdge      (node[0], node[1], node[2] );
+    }
+    break;
+
+  case SMDSAbs_0DElement:
+    if ( nbnode == 1 ) {
+      if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
+      else           e = mesh->Add0DElement      (node[0] );
     }
+    break;
+
+  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());
+    break;
+
+  default:;
   }
   if ( e ) myLastCreatedElems.Append( e );
   return e;
@@ -279,7 +311,7 @@ int SMESH_MeshEditor::Remove (const list< int >& theIDs,
     if ( isNodes ) {
       const SMDS_MeshNode* node = cast2Node( elem );
       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
-        if ( int aShapeID = node->GetPosition()->GetShapeId() )
+        if ( int aShapeID = node->getshapeId() )
           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
             smmap.insert( sm );
     }
@@ -333,46 +365,55 @@ int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
   if ( aMesh->ShapeToMesh().IsNull() )
     return 0;
 
+  int aShapeID = theElem->getshapeId();
+  if ( aShapeID < 1 )
+    return 0;
+
+  if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
+    if ( sm->Contains( theElem ))
+      return aShapeID;
+
   if ( theElem->GetType() == SMDSAbs_Node ) {
-    const SMDS_PositionPtr& aPosition =
-      static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
-    if ( aPosition.get() )
-      return aPosition->GetShapeId();
-    else
-      return 0;
+    MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
+  }
+  else {
+    MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
   }
 
-  TopoDS_Shape aShape; // the shape a node is on
-  SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
-  while ( nodeIt->more() ) {
-    const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
-    const SMDS_PositionPtr& aPosition = node->GetPosition();
-    if ( aPosition.get() ) {
-      int aShapeID = aPosition->GetShapeId();
-      SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
-      if ( sm ) {
-        if ( sm->Contains( theElem ))
-          return aShapeID;
-        if ( aShape.IsNull() )
-          aShape = aMesh->IndexToShape( aShapeID );
-      }
-      else {
-        //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
+  TopoDS_Shape aShape; // the shape a node of theElem is on
+  if ( theElem->GetType() != SMDSAbs_Node )
+  {
+    SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
+    while ( nodeIt->more() ) {
+      const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
+      if ((aShapeID = node->getshapeId()) > 0) {
+        if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
+          if ( sm->Contains( theElem ))
+            return aShapeID;
+          if ( aShape.IsNull() )
+            aShape = aMesh->IndexToShape( aShapeID );
+        }
       }
     }
   }
 
   // None of nodes is on a proper shape,
   // find the shape among ancestors of aShape on which a node is
-  if ( aShape.IsNull() ) {
-    //MESSAGE ("::FindShape() - NONE node is on shape")
-    return 0;
+  if ( !aShape.IsNull() ) {
+    TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
+    for ( ; ancIt.More(); ancIt.Next() ) {
+      SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
+      if ( sm && sm->Contains( theElem ))
+        return aMesh->ShapeToIndex( ancIt.Value() );
+    }
   }
-  TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
-  for ( ; ancIt.More(); ancIt.Next() ) {
-    SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
-    if ( sm && sm->Contains( theElem ))
-      return aMesh->ShapeToIndex( ancIt.Value() );
+  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;
   }
 
   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
@@ -479,15 +520,19 @@ 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();
 
   if (!theTria1 || !theTria2)
     return false;
 
-  const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
-  const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
-  if (F1 && F2) {
+  const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
+  if (!F1) return false;
+  const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
+  if (!F2) return false;
+  if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
+      (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
 
     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
@@ -524,12 +569,14 @@ 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;
     for ( i = 0; i < 6; i++ ) {
-      if ( sameInd [ i ] == 0 )
+      if ( sameInd [ i ] == 0 ) {
         if ( i < 3 ) i1 = i;
         else         i2 = i;
-      else if (i < 3)
+      }
+      else if (i < 3) {
         if ( iA ) iB = i;
         else      iA = i;
+      }
     }
     // nodes 1 and 2 should not be the same
     if ( aNodes[ i1 ] == aNodes[ i2 ] )
@@ -540,24 +587,18 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
     // theTria2: B->1
     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
 
-    //MESSAGE( theTria1 << theTria2 );
-
     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
 
-    //MESSAGE( theTria1 << theTria2 );
-
     return true;
 
   } // end if(F1 && F2)
 
   // check case of quadratic faces
-  const SMDS_QuadraticFaceOfNodes* QF1 =
-    dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
-  if(!QF1) return false;
-  const SMDS_QuadraticFaceOfNodes* QF2 =
-    dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
-  if(!QF2) return false;
+  if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
+    return false;
+  if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
+    return false;
 
   //       5
   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
@@ -622,7 +663,7 @@ static bool findTriangles(const SMDS_MeshNode *    theNode1,
   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
   while (it->more()) {
     const SMDS_MeshElement* elem = it->next();
-    if ( emap.find( elem ) != emap.end() )
+    if ( emap.find( elem ) != emap.end() ) {
       if ( theTria1 ) {
         // theTria1 must be element with minimum ID
         if( theTria1->GetID() < elem->GetID() ) {
@@ -637,6 +678,7 @@ static bool findTriangles(const SMDS_MeshNode *    theNode1,
       else {
         theTria1 = elem;
       }
+    }
   }
   return ( theTria1 && theTria2 );
 }
@@ -660,11 +702,12 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
     return false;
 
-  const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
-  //if (!F1) return false;
-  const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
-  //if (!F2) return false;
-  if (F1 && F2) {
+  const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
+  if (!F1) return false;
+  const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
+  if (!F2) return false;
+  if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
+      (tr2->GetEntityType() == SMDSEntity_Triangle)) {
 
     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
@@ -702,23 +745,13 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
     // tr2: B->1
     aNodes2[ iB2 ] = aNodes1[ i1 ];
 
-    //MESSAGE( tr1 << tr2 );
-
     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
 
-    //MESSAGE( tr1 << tr2 );
-
     return true;
   }
 
   // check case of quadratic faces
-  const SMDS_QuadraticFaceOfNodes* QF1 =
-    dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
-  if(!QF1) return false;
-  const SMDS_QuadraticFaceOfNodes* QF2 =
-    dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
-  if(!QF2) return false;
   return InverseDiag(tr1,tr2);
 }
 
@@ -792,34 +825,39 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
     return false;
 
-  const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
-  //if (!F1) return false;
-  const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
-  //if (!F2) return false;
-  if (F1 && F2) {
+  const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
+  if (!F1) return false;
+  const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
+  if (!F2) return false;
+  SMESHDS_Mesh * aMesh = GetMeshDS();
+
+  if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
+      (tr2->GetEntityType() == SMDSEntity_Triangle)) {
 
     const SMDS_MeshNode* aNodes [ 4 ];
     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
       return false;
 
-    //MESSAGE( endl << tr1 << tr2 );
-
-    GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
-    myLastCreatedElems.Append(tr1);
-    GetMeshDS()->RemoveElement( tr2 );
-
-    //MESSAGE( endl << tr1 );
+    const SMDS_MeshElement* newElem = 0;
+    newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
+    myLastCreatedElems.Append(newElem);
+    AddToSameGroups( newElem, tr1, aMesh );
+    int aShapeId = tr1->getshapeId();
+    if ( aShapeId )
+      {
+        aMesh->SetMeshElementOnShape( newElem, aShapeId );
+      }
+    aMesh->RemoveElement( tr1 );
+    aMesh->RemoveElement( tr2 );
 
     return true;
   }
 
   // check case of quadratic faces
-  const SMDS_QuadraticFaceOfNodes* QF1 =
-    dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
-  if(!QF1) return false;
-  const SMDS_QuadraticFaceOfNodes* QF2 =
-    dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
-  if(!QF2) return false;
+  if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
+    return false;
+  if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
+    return false;
 
   //       5
   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
@@ -849,9 +887,18 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
   aNodes[6] = N2[3];
   aNodes[7] = N1[5];
 
-  GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
-  myLastCreatedElems.Append(tr1);
-  GetMeshDS()->RemoveElement( tr2 );
+  const SMDS_MeshElement* newElem = 0;
+  newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
+                            aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
+  myLastCreatedElems.Append(newElem);
+  AddToSameGroups( newElem, tr1, aMesh );
+  int aShapeId = tr1->getshapeId();
+  if ( aShapeId )
+    {
+      aMesh->SetMeshElementOnShape( newElem, aShapeId );
+    }
+  aMesh->RemoveElement( tr1 );
+  aMesh->RemoveElement( tr2 );
 
   // remove middle node (9)
   GetMeshDS()->RemoveNode( N1[4] );
@@ -866,6 +913,7 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
 
 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
 {
+  MESSAGE("Reorient");
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
@@ -912,8 +960,10 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
   }
   case SMDSAbs_Volume: {
     if (theElem->IsPoly()) {
-      const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
-        static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
+      // TODO reorient vtk polyhedron
+      MESSAGE("reorient vtk polyhedron ?");
+      const SMDS_VtkVolume* aPolyedre =
+        dynamic_cast<const SMDS_VtkVolume*>( theElem );
       if (!aPolyedre) {
         MESSAGE("Warning: bad volumic element");
         return false;
@@ -942,6 +992,7 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
       if ( !vTool.Set( theElem ))
         return false;
       vTool.Inverse();
+      MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
     }
   }
@@ -1014,21 +1065,21 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
 
     int aShapeId = FindShape( elem );
-    const SMDS_MeshElement* newElem = 0;
+    const SMDS_MeshElement* newElem1 = 0;
+    const SMDS_MeshElement* newElem2 = 0;
 
     if( !elem->IsQuadratic() ) {
 
       // split liner quadrangle
-
       if ( aBadRate1 <= aBadRate2 ) {
         // tr1 + tr2 is better
-        aMesh->ChangeElementNodes( elem, aNodes, 3 );
-        newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
+        newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
+        newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
       }
       else {
         // tr3 + tr4 is better
-        aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
-        newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
+        newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
+        newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
       }
     }
     else {
@@ -1081,39 +1132,34 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
       myLastCreatedNodes.Append(newN);
 
       // create a new element
-      const SMDS_MeshNode* N[6];
       if ( aBadRate1 <= aBadRate2 ) {
-        N[0] = aNodes[0];
-        N[1] = aNodes[1];
-        N[2] = aNodes[2];
-        N[3] = aNodes[4];
-        N[4] = aNodes[5];
-        N[5] = newN;
-        newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
-                                 aNodes[6], aNodes[7], newN );
+        newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
+                                  aNodes[6], aNodes[7], newN );
+        newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
+                                  newN,      aNodes[4], aNodes[5] );
       }
       else {
-        N[0] = aNodes[1];
-        N[1] = aNodes[2];
-        N[2] = aNodes[3];
-        N[3] = aNodes[5];
-        N[4] = aNodes[6];
-        N[5] = newN;
-        newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
-                                 aNodes[7], aNodes[4], newN );
+        newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
+                                  aNodes[7], aNodes[4], newN );
+        newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
+                                  newN,      aNodes[5], aNodes[6] );
       }
-      aMesh->ChangeElementNodes( elem, N, 6 );
-
     } // quadratic case
 
     // care of a new element
 
-    myLastCreatedElems.Append(newElem);
-    AddToSameGroups( newElem, elem, aMesh );
+    myLastCreatedElems.Append(newElem1);
+    myLastCreatedElems.Append(newElem2);
+    AddToSameGroups( newElem1, elem, aMesh );
+    AddToSameGroups( newElem2, elem, aMesh );
 
     // put a new triangle on the same shape
     if ( aShapeId )
-      aMesh->SetMeshElementOnShape( newElem, aShapeId );
+      {
+        aMesh->SetMeshElementOnShape( newElem1, aShapeId );
+        aMesh->SetMeshElementOnShape( newElem2, aShapeId );
+      }
+    aMesh->RemoveElement( elem );
   }
   return true;
 }
@@ -1516,14 +1562,14 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
                                               const int                theMethodFlags)
 {
   // std-like iterator on coordinates of nodes of mesh element
-  typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
+  typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
   NXyzIterator xyzEnd;
 
   SMDS_VolumeTool    volTool;
   SMESH_MesherHelper helper( *GetMesh());
 
-  SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
-  SMESHDS_SubMesh* fSubMesh = subMesh;
+  SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
+  SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
   
   SMESH_SequenceOfElemPtr newNodes, newElems;
 
@@ -1569,6 +1615,7 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
       helper.SetIsQuadratic( false );
     }
     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
+    helper.SetElementsOnShape( true );
     if ( splitMethod._baryNode )
     {
       // make a node at barycenter
@@ -1596,7 +1643,6 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
     }
 
     // make tetras
-    helper.SetElementsOnShape( true );
     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 )
@@ -1624,6 +1670,12 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
         helper.SetElementsOnShape( false );
         vector< const SMDS_MeshElement* > triangles;
 
+        // find submesh to add new triangles in
+        if ( !fSubMesh || !fSubMesh->Contains( face ))
+        {
+          int shapeID = FindShape( face );
+          fSubMesh = GetMeshDS()->MeshElements( shapeID );
+        }
         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
         if ( iF_n != splitMethod._faceBaryNode.end() )
         {
@@ -1635,6 +1687,9 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
             if ( !volTool.IsFaceExternal( iF ))
               swap( n2, n3 );
             triangles.push_back( helper.AddFace( n1,n2,n3 ));
+
+            if ( fSubMesh && n3->getshapeId() < 1 )
+              fSubMesh->AddNode( n3 );
           }
         }
         else
@@ -1673,18 +1728,12 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
                                                  volNodes[ facet->_n3 ]));
           }
         }
-        // find submesh to add new triangles in
-        if ( !fSubMesh || !fSubMesh->Contains( face ))
-        {
-          int shapeID = FindShape( face );
-          fSubMesh = GetMeshDS()->MeshElements( shapeID );
-        }
         for ( int i = 0; i < triangles.size(); ++i )
         {
-          if ( !triangles.back() ) continue;
+          if ( !triangles[i] ) continue;
           if ( fSubMesh )
-            fSubMesh->AddElement( triangles.back());
-          newElems.Append( triangles.back() );
+            fSubMesh->AddElement( triangles[i]);
+          newElems.Append( triangles[i] );
         }
         ReplaceElemInGroups( face, triangles, GetMeshDS() );
         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
@@ -1821,20 +1870,28 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
 
       int aShapeId = FindShape( elem );
-      const SMDS_MeshElement* newElem = 0;
+      const SMDS_MeshElement* newElem1 = 0;
+      const SMDS_MeshElement* newElem2 = 0;
       if ( the13Diag ) {
-        aMesh->ChangeElementNodes( elem, aNodes, 3 );
-        newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
+        newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
+        newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
       }
       else {
-        aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
-        newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
+        newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
+        newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
       }
-      myLastCreatedElems.Append(newElem);
+      myLastCreatedElems.Append(newElem1);
+      myLastCreatedElems.Append(newElem2);
       // put a new triangle on the same shape and add to the same groups
       if ( aShapeId )
-        aMesh->SetMeshElementOnShape( newElem, aShapeId );
-      AddToSameGroups( newElem, elem, aMesh );
+        {
+          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
@@ -1889,34 +1946,31 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
       myLastCreatedNodes.Append(newN);
 
       // create a new element
-      const SMDS_MeshElement* newElem = 0;
-      const SMDS_MeshNode* N[6];
+      const SMDS_MeshElement* newElem1 = 0;
+      const SMDS_MeshElement* newElem2 = 0;
       if ( the13Diag ) {
-        N[0] = aNodes[0];
-        N[1] = aNodes[1];
-        N[2] = aNodes[2];
-        N[3] = aNodes[4];
-        N[4] = aNodes[5];
-        N[5] = newN;
-        newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
-                                 aNodes[6], aNodes[7], newN );
+        newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
+                                  aNodes[6], aNodes[7], newN );
+        newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
+                                  newN,      aNodes[4], aNodes[5] );
       }
       else {
-        N[0] = aNodes[1];
-        N[1] = aNodes[2];
-        N[2] = aNodes[3];
-        N[3] = aNodes[5];
-        N[4] = aNodes[6];
-        N[5] = newN;
-        newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
-                                 aNodes[7], aNodes[4], newN );
+        newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
+                                  aNodes[7], aNodes[4], newN );
+        newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
+                                  newN,      aNodes[5], aNodes[6] );
       }
-      myLastCreatedElems.Append(newElem);
-      aMesh->ChangeElementNodes( elem, N, 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( newElem, aShapeId );
-      AddToSameGroups( newElem, elem, aMesh );
+        {
+          aMesh->SetMeshElementOnShape( newElem1, aShapeId );
+          aMesh->SetMeshElementOnShape( newElem2, aShapeId );
+        }
+      AddToSameGroups( newElem1, elem, aMesh );
+      AddToSameGroups( newElem2, elem, aMesh );
+      aMesh->RemoveElement( elem );
     }
   }
 
@@ -1962,7 +2016,7 @@ double getAngle(const SMDS_MeshElement * tr1,
     int i = 0, iDiag = -1;
     while ( it->more()) {
       const SMDS_MeshElement *n = it->next();
-      if ( n == n1 || n == n2 )
+      if ( n == n1 || n == n2 ) {
         if ( iDiag < 0)
           iDiag = i;
         else {
@@ -1972,6 +2026,7 @@ double getAngle(const SMDS_MeshElement * tr1,
             nFirst[ t ] = n;
           break;
         }
+      }
       i++;
     }
   }
@@ -2212,16 +2267,17 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
           mapEl_setLi.erase( tr2 );
           mapLi_listEl.erase( *link12 );
           if(tr1->NbNodes()==3) {
-            if( tr1->GetID() < tr2->GetID() ) {
-              aMesh->ChangeElementNodes( tr1, n12, 4 );
-              myLastCreatedElems.Append(tr1);
-              aMesh->RemoveElement( tr2 );
-            }
-            else {
-              aMesh->ChangeElementNodes( tr2, n12, 4 );
-              myLastCreatedElems.Append(tr2);
-              aMesh->RemoveElement( tr1);
-            }
+            const SMDS_MeshElement* newElem = 0;
+            newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
+            myLastCreatedElems.Append(newElem);
+            AddToSameGroups( newElem, tr1, aMesh );
+            int aShapeId = tr1->getshapeId();
+            if ( aShapeId )
+              {
+                aMesh->SetMeshElementOnShape( newElem, aShapeId );
+              }
+            aMesh->RemoveElement( tr1 );
+            aMesh->RemoveElement( tr2 );
           }
           else {
             const SMDS_MeshNode* N1 [6];
@@ -2239,16 +2295,18 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
             aNodes[5] = N2[5];
             aNodes[6] = N2[3];
             aNodes[7] = N1[5];
-            if( tr1->GetID() < tr2->GetID() ) {
-              GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
-              myLastCreatedElems.Append(tr1);
-              GetMeshDS()->RemoveElement( tr2 );
-            }
-            else {
-              GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
-              myLastCreatedElems.Append(tr2);
-              GetMeshDS()->RemoveElement( tr1 );
-            }
+            const SMDS_MeshElement* newElem = 0;
+            newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
+                                     aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
+            myLastCreatedElems.Append(newElem);
+            AddToSameGroups( newElem, tr1, aMesh );
+            int aShapeId = tr1->getshapeId();
+            if ( aShapeId )
+              {
+                aMesh->SetMeshElementOnShape( newElem, aShapeId );
+              }
+            aMesh->RemoveElement( tr1 );
+            aMesh->RemoveElement( tr2 );
             // remove middle node (9)
             GetMeshDS()->RemoveNode( N1[4] );
           }
@@ -2257,16 +2315,17 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
           mapEl_setLi.erase( tr3 );
           mapLi_listEl.erase( *link13 );
           if(tr1->NbNodes()==3) {
-            if( tr1->GetID() < tr2->GetID() ) {
-              aMesh->ChangeElementNodes( tr1, n13, 4 );
-              myLastCreatedElems.Append(tr1);
-              aMesh->RemoveElement( tr3 );
-            }
-            else {
-              aMesh->ChangeElementNodes( tr3, n13, 4 );
-              myLastCreatedElems.Append(tr3);
-              aMesh->RemoveElement( tr1 );
-            }
+            const SMDS_MeshElement* newElem = 0;
+            newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
+            myLastCreatedElems.Append(newElem);
+            AddToSameGroups( newElem, tr1, aMesh );
+            int aShapeId = tr1->getshapeId();
+            if ( aShapeId )
+              {
+                aMesh->SetMeshElementOnShape( newElem, aShapeId );
+              }
+            aMesh->RemoveElement( tr1 );
+            aMesh->RemoveElement( tr3 );
           }
           else {
             const SMDS_MeshNode* N1 [6];
@@ -2284,16 +2343,18 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
             aNodes[5] = N2[5];
             aNodes[6] = N2[3];
             aNodes[7] = N1[5];
-            if( tr1->GetID() < tr2->GetID() ) {
-              GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
-              myLastCreatedElems.Append(tr1);
-              GetMeshDS()->RemoveElement( tr3 );
-            }
-            else {
-              GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
-              myLastCreatedElems.Append(tr3);
-              GetMeshDS()->RemoveElement( tr1 );
-            }
+            const SMDS_MeshElement* newElem = 0;
+            newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
+                                     aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
+            myLastCreatedElems.Append(newElem);
+            AddToSameGroups( newElem, tr1, aMesh );
+            int aShapeId = tr1->getshapeId();
+            if ( aShapeId )
+              {
+                aMesh->SetMeshElementOnShape( newElem, aShapeId );
+              }
+            aMesh->RemoveElement( tr1 );
+            aMesh->RemoveElement( tr3 );
             // remove middle node (9)
             GetMeshDS()->RemoveNode( N1[4] );
           }
@@ -2609,6 +2670,9 @@ void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
   while ( elemIt->more() )
   {
     const SMDS_MeshElement* elem = elemIt->next();
+    if(elem->GetType() == SMDSAbs_0DElement)
+      continue;
+    
     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
     if ( elem->GetType() == SMDSAbs_Volume )
     {
@@ -2841,7 +2905,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
     Handle(Geom_Surface) surface;
     SMESHDS_SubMesh* faceSubMesh = 0;
     TopoDS_Face face;
-    double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
+    double fToler2 = 0, f,l;
     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
     bool isUPeriodic = false, isVPeriodic = false;
     if ( *fId ) {
@@ -2852,10 +2916,10 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
       fToler2 *= fToler2 * 10.;
       isUPeriodic = surface->IsUPeriodic();
       if ( isUPeriodic )
-        vPeriod = surface->UPeriod();
+        surface->UPeriod();
       isVPeriodic = surface->IsVPeriodic();
       if ( isVPeriodic )
-        uPeriod = surface->VPeriod();
+        surface->VPeriod();
       surface->Bounds( u1, u2, v1, v2 );
     }
     // ---------------------------------------------------------
@@ -2905,7 +2969,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
       while ( nn++ < nbn ) {
         node = static_cast<const SMDS_MeshNode*>( itN->next() );
         const SMDS_PositionPtr& pos = node->GetPosition();
-        posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
+        posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
         if (posType != SMDS_TOP_EDGE &&
             posType != SMDS_TOP_VERTEX &&
             theFixedNodes.find( node ) == theFixedNodes.end())
@@ -2963,27 +3027,27 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
         node = *n;
         gp_XY uv( 0, 0 );
         const SMDS_PositionPtr& pos = node->GetPosition();
-        posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
+        posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
         // get existing UV
         switch ( posType ) {
         case SMDS_TOP_FACE: {
-          SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
+          SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
           break;
         }
         case SMDS_TOP_EDGE: {
-          TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
+          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.get() )->GetUParameter();
+            double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
             uv = pcurve->Value( u ).XY();
           }
           break;
         }
         case SMDS_TOP_VERTEX: {
-          TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
+          TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
           break;
@@ -3027,35 +3091,27 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
     // fix nodes on mesh boundary
 
     if ( checkBoundaryNodes ) {
-      map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
-      map< NLink, int >::iterator link_nb;
+      map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
+      map< SMESH_TLink, int >::iterator link_nb;
       // put all elements links to linkNbMap
       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
         const SMDS_MeshElement* elem = (*elemIt);
-        int nbn =  elem->NbNodes();
-        if(elem->IsQuadratic())
-          nbn = nbn/2;
+        int nbn =  elem->NbCornerNodes();
         // loop on elem links: insert them in linkNbMap
-        const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
         for ( int iN = 0; iN < nbn; ++iN ) {
-          curNode = elem->GetNode( iN );
-          NLink link;
-          if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
-          else                      link = make_pair( prevNode , curNode );
-          prevNode = curNode;
-          link_nb = linkNbMap.find( link );
-          if ( link_nb == linkNbMap.end() )
-            linkNbMap.insert( make_pair ( link, 1 ));
-          else
-            link_nb->second++;
+          const SMDS_MeshNode* n1 = elem->GetNode( iN );
+          const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
+          SMESH_TLink link( n1, n2 );
+          link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
+          link_nb->second++;
         }
       }
       // remove nodes that are in links encountered only once from setMovableNodes
       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
         if ( link_nb->second == 1 ) {
-          setMovableNodes.erase( link_nb->first.first );
-          setMovableNodes.erase( link_nb->first.second );
+          setMovableNodes.erase( link_nb->first.node1() );
+          setMovableNodes.erase( link_nb->first.node2() );
         }
       }
     }
@@ -3246,7 +3302,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
       if ( node_uv != uvMap.end() ) {
         gp_XY* uv = node_uv->second;
         node->SetPosition
-          ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
+          ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
       }
     }
 
@@ -3258,14 +3314,14 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
         helper.SetSubShape( face );
       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
-        const SMDS_QuadraticFaceOfNodes* QF =
-          dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
-        if(QF) {
+        const SMDS_VtkFace* QF =
+          dynamic_cast<const SMDS_VtkFace*> (*elemIt);
+        if(QF && QF->IsQuadratic()) {
           vector<const SMDS_MeshNode*> Ns;
           Ns.reserve(QF->NbNodes()+1);
-          SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
+          SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
           while ( anIter->more() )
-            Ns.push_back( anIter->next() );
+            Ns.push_back( cast2Node(anIter->next()) );
           Ns.push_back( Ns[0] );
           double x, y, z;
           for(int i=0; i<QF->NbNodes(); i=i+2) {
@@ -3343,6 +3399,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
                                     const int                             nbSteps,
                                     SMESH_SequenceOfElemPtr&              srcElements)
 {
+  //MESSAGE("sweepElement " << nbSteps);
   SMESHDS_Mesh* aMesh = GetMeshDS();
 
   // Loop on elem nodes:
@@ -3381,7 +3438,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
     }
   }
 
-  //cout<<"  nbSame = "<<nbSame<<endl;
+  //cerr<<"  nbSame = "<<nbSame<<endl;
   if ( nbSame == nbNodes || nbSame > 2) {
     MESSAGE( " Too many same nodes of element " << elem->GetID() );
     //INFOS( " Too many same nodes of element " << elem->GetID() );
@@ -3418,6 +3475,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
   }
 
   // make new elements
+  const SMDS_MeshElement* lastElem = elem;
   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
     // get next nodes
     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
@@ -3433,7 +3491,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
           nextNod[ iNode ] = *itNN[ iNode ];
           itNN[ iNode ]++;
         }
-        else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
+        else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
           // we have to use each second node
           //itNN[ iNode ]++;
           nextNod[ iNode ] = *itNN[ iNode ];
@@ -3738,6 +3796,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
       newElems.push_back( aNewElem );
       myLastCreatedElems.Append(aNewElem);
       srcElements.Append( elem );
+      lastElem = aNewElem;
     }
 
     // set new prev nodes
@@ -3766,6 +3825,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
                                   const int                nbSteps,
                                   SMESH_SequenceOfElemPtr& srcElements)
 {
+  MESSAGE("makeWalls");
   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
   SMESHDS_Mesh* aMesh = GetMeshDS();
 
@@ -3809,6 +3869,8 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
     const SMDS_MeshElement* elem = itElem->first;
     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
 
+    if(itElem->second.size()==0) continue;
+
     if ( elem->GetType() == SMDSAbs_Edge ) {
       // create a ceiling edge
       if (!elem->IsQuadratic()) {
@@ -3833,8 +3895,6 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
     if ( elem->GetType() != SMDSAbs_Face )
       continue;
 
-    if(itElem->second.size()==0) continue;
-
     bool hasFreeLinks = false;
 
     TIDSortedElemSet avoidSet;
@@ -3954,79 +4014,111 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
           vTool.Set( *v );
           vTool.SetExternalNormal();
+          const int nextShift = vTool.IsForward() ? +1 : -1;
           list< int >::iterator ind = freeInd.begin();
           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
           {
             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
             int nbn = vTool.NbFaceNodes( *ind );
-            switch ( nbn ) {
-            case 3: { ///// triangle
-              const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
-              if ( !f )
-                myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
-              else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
-                aMesh->ChangeElementNodes( f, nodes, nbn );
-              break;
-            }
-            case 4: { ///// quadrangle
-              const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
-              if ( !f )
-                myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
-              else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
-                aMesh->ChangeElementNodes( f, nodes, nbn );
-              break;
-            }
-            default:
-              if( (*v)->IsQuadratic() ) {
-                if(nbn==6) { /////// quadratic triangle
-                  const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
-                                                             nodes[1], nodes[3], nodes[5] );
-                  if ( !f ) {
-                    myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
-                                                             nodes[1], nodes[3], nodes[5]));
-                  }
-                  else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
-                    const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
-                    tmpnodes[0] = nodes[0];
-                    tmpnodes[1] = nodes[2];
-                    tmpnodes[2] = nodes[4];
-                    tmpnodes[3] = nodes[1];
-                    tmpnodes[4] = nodes[3];
-                    tmpnodes[5] = nodes[5];
-                    aMesh->ChangeElementNodes( f, tmpnodes, nbn );
-                  }
+            if ( ! (*v)->IsPoly() )
+              switch ( nbn ) {
+              case 3: { ///// triangle
+                const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
+                if ( !f ||
+                     nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
+                {
+                  const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
+                                                       nodes[ 1 ],
+                                                       nodes[ 1 + nextShift ] };
+                  if ( f )
+                    aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
+                  else
+                    myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
+                                                              newOrder[ 2 ] ));
                 }
-                else {       /////// quadratic quadrangle
-                  const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
-                                                             nodes[1], nodes[3], nodes[5], nodes[7] );
-                  if ( !f ) {
-                    myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
-                                                             nodes[1], nodes[3], nodes[5], nodes[7]));
-                  }
-                  else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
-                    const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
-                    tmpnodes[0] = nodes[0];
-                    tmpnodes[1] = nodes[2];
-                    tmpnodes[2] = nodes[4];
-                    tmpnodes[3] = nodes[6];
-                    tmpnodes[4] = nodes[1];
-                    tmpnodes[5] = nodes[3];
-                    tmpnodes[6] = nodes[5];
-                    tmpnodes[7] = nodes[7];
-                    aMesh->ChangeElementNodes( f, tmpnodes, nbn );
-                  }
+                break;
+              }
+              case 4: { ///// quadrangle
+                const SMDS_MeshFace * f =
+                  aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
+                if ( !f ||
+                     nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
+                {
+                  const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
+                                                       nodes[ 2 ], nodes[ 2+nextShift ] };
+                  if ( f )
+                    aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
+                  else
+                    myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
+                                                              newOrder[ 2 ], newOrder[ 3 ]));
+                }
+                break;
+              }
+              case 6: { /////// quadratic triangle
+                const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
+                                                           nodes[1], nodes[3], nodes[5] );
+                if ( !f ||
+                     nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
+                {
+                  const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
+                                                       nodes[2],
+                                                       nodes[2 + 2*nextShift],
+                                                       nodes[3 - 2*nextShift],
+                                                       nodes[3],
+                                                       nodes[3 + 2*nextShift]};
+                  if ( f )
+                    aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
+                  else
+                    myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
+                                                              newOrder[ 1 ],
+                                                              newOrder[ 2 ],
+                                                              newOrder[ 3 ],
+                                                              newOrder[ 4 ],
+                                                              newOrder[ 5 ] ));
                 }
+                break;
               }
-              else { //////// polygon
-                vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
-                const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
-                if ( !f )
-                  myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
-                else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
-                  aMesh->ChangeElementNodes( f, nodes, nbn );
+              default:       /////// quadratic quadrangle
+                const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
+                                                           nodes[1], nodes[3], nodes[5], nodes[7] );
+                if ( !f ||
+                     nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
+                {
+                  const SMDS_MeshNode* newOrder[8] = { nodes[0],
+                                                       nodes[4 - 2*nextShift],
+                                                       nodes[4],
+                                                       nodes[4 + 2*nextShift],
+                                                       nodes[1],
+                                                       nodes[5 - 2*nextShift],
+                                                       nodes[5],
+                                                       nodes[5 + 2*nextShift] };
+                  if ( f )
+                    aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
+                  else
+                    myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
+                                                             newOrder[ 2 ], newOrder[ 3 ],
+                                                             newOrder[ 4 ], newOrder[ 5 ],
+                                                             newOrder[ 6 ], newOrder[ 7 ]));
+                }
+              } // switch ( nbn )
+
+            else { //////// polygon
+
+              vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
+              const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
+              if ( !f ||
+                   nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
+              {
+                if ( !vTool.IsForward() )
+                  std::reverse( polygon_nodes.begin(), polygon_nodes.end());
+                if ( f )
+                  aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
+                else
+                  AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
               }
             }
+
             while ( srcElements.Length() < myLastCreatedElems.Length() )
               srcElements.Append( *srcEdge );
 
@@ -4035,8 +4127,9 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
           // go to the next volume
           iVol = 0;
           while ( iVol++ < nbVolumesByStep ) v++;
-        }
-      }
+
+        } // loop on steps
+      } // loop on volumes of one step
     } // sweep free links into faces
 
     // Make a ceiling face with a normal external to a volume
@@ -4322,6 +4415,7 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
                                   const int           theFlags,
                                   const double        theTolerance)
 {
+  MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
@@ -4522,6 +4616,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
                                        const gp_Pnt&        theRefPoint,
                                        const bool           theMakeGroups)
 {
+  MESSAGE("ExtrusionAlongTrack");
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
@@ -4580,7 +4675,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
     while ( aItN->more() ) {
       const SMDS_MeshNode* pNode = aItN->next();
       const SMDS_EdgePosition* pEPos =
-        static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
+        static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
       double aT = pEPos->GetUParameter();
       aPrms.push_back( aT );
     }
@@ -4624,7 +4719,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
         while ( aItN->more() ) {
           const SMDS_MeshNode* pNode = aItN->next();
           const SMDS_EdgePosition* pEPos =
-            static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
+            static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
           double aT = pEPos->GetUParameter();
           aPrms.push_back( aT );
         }
@@ -4752,7 +4847,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
       const SMDS_MeshNode* pNode = aItN->next();
       if( pNode==aN1 || pNode==aN2 ) continue;
       const SMDS_EdgePosition* pEPos =
-        static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
+        static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
       double aT = pEPos->GetUParameter();
       aPrms.push_back( aT );
     }
@@ -4799,7 +4894,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
         while ( aItN->more() ) {
           const SMDS_MeshNode* pNode = aItN->next();
           const SMDS_EdgePosition* pEPos =
-            static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
+            static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
           double aT = pEPos->GetUParameter();
           aPrms.push_back( aT );
         }
@@ -4827,9 +4922,6 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
       itPP = currList.begin();
       SMESH_MeshEditor_PathPoint PP2 = currList.front();
-      gp_Pnt P1 = PP1.Pnt();
-      //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
-      gp_Pnt P2 = PP2.Pnt();
       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,
@@ -4925,6 +5017,7 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
                                    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);
@@ -5080,6 +5173,7 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
           }
 
           // 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.;
@@ -5209,7 +5303,7 @@ void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
  *  \param theCopy - if true, create translated copies of theElems
  *  \param theMakeGroups - if true and theCopy, create translated groups
  *  \param theTargetMesh - mesh to copy translated elements into
- *  \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
+ *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
  */
 //================================================================================
 
@@ -5227,22 +5321,37 @@ 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";
   }
@@ -5263,8 +5372,7 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
   SMESH_SequenceOfElemPtr srcElems, srcNodes;
 
   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
-  list<SMDS_MeshNode>          orphanCopy; // copies of orphan nodes
-  vector<const SMDS_MeshNode*> orphanNode; // original orphan nodes
+  TIDSortedElemSet orphanNode;
 
   if ( theElems.empty() ) // transform the whole mesh
   {
@@ -5272,28 +5380,20 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
     while ( eIt->more() ) theElems.insert( eIt->next() );
     // add orphan nodes
-    SMDS_MeshElementIDFactory idFactory;
     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
     while ( nIt->more() )
     {
       const SMDS_MeshNode* node = nIt->next();
-      if ( node->NbInverseElements() == 0 && !theElems.insert( node ).second )
-      {
-        // node was not inserted into theElems because an element with the same ID
-        // is already there. As a work around we insert a copy of node with
-        // an ID = -<index in orphanNode>
-        orphanCopy.push_back( *node ); // copy node
-        SMDS_MeshNode* nodeCopy = &orphanCopy.back();
-        int uniqueID = -orphanNode.size();
-        orphanNode.push_back( node );
-        idFactory.BindID( uniqueID, nodeCopy );
-        theElems.insert( nodeCopy );
-      }
+      if ( node->NbInverseElements() == 0)
+        orphanNode.insert( node );
     }
   }
-  // loop on theElems to transorm nodes
+
+  // loop on elements to transform nodes : first orphan nodes then elems
   TIDSortedElemSet::iterator itElem;
-  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+  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;
@@ -5303,8 +5403,6 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
     while ( itN->more() ) {
 
       const SMDS_MeshNode* node = cast2Node( itN->next() );
-      if ( node->GetID() < 0 )
-        node = orphanNode[ -node->GetID() ];
       // check if a node has been already transformed
       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
         nodeMap.insert( make_pair ( node, node ));
@@ -5355,7 +5453,7 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
     theElems.insert( *invElemIt );
 
   // replicate or reverse elements
-
+  // TODO revoir ordre reverse vtk
   enum {
     REV_TETRA   = 0,  //  = nbNodes - 4
     REV_PYRAMID = 1,  //  = nbNodes - 4
@@ -5423,8 +5521,8 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
       case SMDSAbs_Volume:
         {
           // ATTENTION: Reversing is not yet done!!!
-          const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
-            dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
+          const SMDS_VtkVolume* aPolyedre =
+            dynamic_cast<const SMDS_VtkVolume*>( elem );
           if (!aPolyedre) {
             MESSAGE("Warning: bad volumic element");
             continue;
@@ -5471,12 +5569,12 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
 
     // Regular elements
     int* i = index[ FORWARD ];
-    if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
+    if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
       if ( elemType == SMDSAbs_Face )
         i = index[ REV_FACE ];
       else
         i = index[ nbNodes - 4 ];
-
+    }
     if(elem->IsQuadratic()) {
       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
       i = anIds;
@@ -5547,13 +5645,339 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
 
   PGroupIDs newGroupIDs;
 
-  if ( theMakeGroups && theCopy ||
-       theMakeGroups && theTargetMesh )
+  if ( ( theMakeGroups && theCopy ) ||
+       ( theMakeGroups && theTargetMesh ) )
     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
 
   return newGroupIDs;
 }
 
+
+////=======================================================================
+////function : Scale
+////purpose  :
+////=======================================================================
+//
+//SMESH_MeshEditor::PGroupIDs
+//SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
+//                         const gp_Pnt&            thePoint,
+//                         const std::list<double>& theScaleFact,
+//                         const bool         theCopy,
+//                         const bool         theMakeGroups,
+//                         SMESH_Mesh*        theTargetMesh)
+//{
+//  MESSAGE("Scale");
+//  myLastCreatedElems.Clear();
+//  myLastCreatedNodes.Clear();
+//
+//  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
+//  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
+//  SMESHDS_Mesh* aMesh    = GetMeshDS();
+//
+//  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
+//  std::list<double>::const_iterator itS = theScaleFact.begin();
+//  scaleX = (*itS);
+//  if(theScaleFact.size()==1) {
+//    scaleY = (*itS);
+//    scaleZ= (*itS);
+//  }
+//  if(theScaleFact.size()==2) {
+//    itS++;
+//    scaleY = (*itS);
+//    scaleZ= (*itS);
+//  }
+//  if(theScaleFact.size()>2) {
+//    itS++;
+//    scaleY = (*itS);
+//    itS++;
+//    scaleZ= (*itS);
+//  }
+//
+//  // map old node to new one
+//  TNodeNodeMap nodeMap;
+//
+//  // elements sharing moved nodes; those of them which have all
+//  // nodes mirrored but are not in theElems are to be reversed
+//  TIDSortedElemSet inverseElemSet;
+//
+//  // source elements for each generated one
+//  SMESH_SequenceOfElemPtr srcElems, srcNodes;
+//
+//  // loop on theElems
+//  TIDSortedElemSet::iterator itElem;
+//  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+//    const SMDS_MeshElement* elem = *itElem;
+//    if ( !elem )
+//      continue;
+//
+//    // loop on elem nodes
+//    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+//    while ( itN->more() ) {
+//
+//      // check if a node has been already transformed
+//      const SMDS_MeshNode* node = cast2Node( itN->next() );
+//      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
+//        nodeMap.insert( make_pair ( node, node ));
+//      if ( !n2n_isnew.second )
+//        continue;
+//
+//      //double coord[3];
+//      //coord[0] = node->X();
+//      //coord[1] = node->Y();
+//      //coord[2] = node->Z();
+//      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
+//      double dx = (node->X() - thePoint.X()) * scaleX;
+//      double dy = (node->Y() - thePoint.Y()) * scaleY;
+//      double dz = (node->Z() - thePoint.Z()) * scaleZ;
+//      if ( theTargetMesh ) {
+//        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
+//        const SMDS_MeshNode * newNode =
+//          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
+//        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] );
+//        const SMDS_MeshNode * newNode =
+//          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
+//        n2n_isnew.first->second = newNode;
+//        myLastCreatedNodes.Append(newNode);
+//        srcNodes.Append( node );
+//      }
+//      else {
+//        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
+//        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
+//        // 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 );
+//      //  }
+//      //}
+//    }
+//  }
+//
+//  // either create new elements or reverse mirrored ones
+//  //if ( !theCopy && !needReverse && !theTargetMesh )
+//  if ( !theCopy && !theTargetMesh )
+//    return PGroupIDs();
+//
+//  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
+//  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
+//    theElems.insert( *invElemIt );
+//
+//  // replicate or reverse elements
+//
+//  enum {
+//    REV_TETRA   = 0,  //  = nbNodes - 4
+//    REV_PYRAMID = 1,  //  = nbNodes - 4
+//    REV_PENTA   = 2,  //  = nbNodes - 4
+//    REV_FACE    = 3,
+//    REV_HEXA    = 4,  //  = nbNodes - 4
+//    FORWARD     = 5
+//  };
+//  int index[][8] = {
+//    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
+//    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
+//    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
+//    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
+//    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
+//    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
+//  };
+//
+//  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
+//  {
+//    const SMDS_MeshElement* elem = *itElem;
+//    if ( !elem || elem->GetType() == SMDSAbs_Node )
+//      continue;
+//
+//    int nbNodes = elem->NbNodes();
+//    int elemType = elem->GetType();
+//
+//    if (elem->IsPoly()) {
+//      // Polygon or Polyhedral Volume
+//      switch ( elemType ) {
+//      case SMDSAbs_Face:
+//        {
+//          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());
+//            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 SMDSAbs_Volume:
+//        {
+//          // ATTENTION: Reversing is not yet done!!!
+//          const SMDS_VtkVolume* aPolyedre =
+//            dynamic_cast<const SMDS_VtkVolume*>( elem );
+//          if (!aPolyedre) {
+//            MESSAGE("Warning: bad volumic element");
+//            continue;
+//          }
+//
+//          vector<const SMDS_MeshNode*> poly_nodes;
+//          vector<int> quantities;
+//
+//          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);
+//              }
+//            }
+//            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;
+//      default:;
+//      }
+//      continue;
+//    }
+//
+//    // Regular elements
+//    int* i = index[ FORWARD ];
+//    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
+//    //  if ( elemType == SMDSAbs_Face )
+//    //    i = index[ REV_FACE ];
+//    //  else
+//    //    i = index[ nbNodes - 4 ];
+//
+//    if(elem->IsQuadratic()) {
+//      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
+//      i = anIds;
+//      //if(needReverse) {
+//      //  if(nbNodes==3) { // quadratic edge
+//      //    static int anIds[] = {1,0,2};
+//      //    i = anIds;
+//      //  }
+//      //  else if(nbNodes==6) { // quadratic triangle
+//      //    static int anIds[] = {0,2,1,5,4,3};
+//      //    i = anIds;
+//      //  }
+//      //  else if(nbNodes==8) { // quadratic quadrangle
+//      //    static int anIds[] = {0,3,2,1,7,6,5,4};
+//      //    i = anIds;
+//      //  }
+//      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
+//      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
+//      //    i = anIds;
+//      //  }
+//      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
+//      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
+//      //    i = anIds;
+//      //  }
+//      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
+//      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
+//      //    i = anIds;
+//      //  }
+//      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
+//      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
+//      //    i = anIds;
+//      //  }
+//      //}
+//    }
+//
+//    // find transformed nodes
+//    vector<const SMDS_MeshNode*> nodes(nbNodes);
+//    int iNode = 0;
+//    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+//    while ( itN->more() ) {
+//      const SMDS_MeshNode* node =
+//        static_cast<const SMDS_MeshNode*>( itN->next() );
+//      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
+//      if ( nodeMapIt == nodeMap.end() )
+//        break; // not all nodes transformed
+//      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
+//    }
+//    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 ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
+//        myLastCreatedElems.Append( copy );
+//        srcElems.Append( elem );
+//      }
+//    }
+//    else {
+//      // reverse element as it was reversed by transformation
+//      if ( nbNodes > 2 )
+//        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
+//    }
+//  }
+//
+//  PGroupIDs newGroupIDs;
+//
+//  if ( theMakeGroups && theCopy ||
+//       theMakeGroups && theTargetMesh ) {
+//    string groupPostfix = "scaled";
+//    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
+//  }
+//
+//  return newGroupIDs;
+//}
+
+
 //=======================================================================
 /*!
  * \brief Create groups of elements made during transformation
@@ -5757,9 +6181,8 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
    */
   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
   {
-    SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
     map<double, const SMDS_MeshNode*> dist2Nodes;
-    myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
+    myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
     if ( !dist2Nodes.empty() )
       return dist2Nodes.begin()->second;
     list<const SMDS_MeshNode*> nodes;
@@ -5775,14 +6198,14 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
       list< SMESH_OctreeNode* >::iterator trIt;
       treeList.push_back( myOctreeNode );
 
-      SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
-      bool pointInside = myOctreeNode->isInside( &pointNode, myHalfLeafSize );
+      gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
+      bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
       {
         SMESH_OctreeNode* tree = *trIt;
         if ( !tree->isLeaf() ) // put children to the queue
         {
-          if ( pointInside && !tree->isInside( &pointNode, myHalfLeafSize )) continue;
+          if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
           while ( cIt->more() )
             treeList.push_back( cIt->next() );
@@ -5818,7 +6241,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
     const SMDS_MeshNode* closestNode = 0;
     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
     for ( ; nIt != nodes.end(); ++nIt ) {
-      double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
+      double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
       if ( minSqDist > sqDist ) {
         closestNode = *nIt;
         minSqDist = sqDist;
@@ -5873,7 +6296,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
   {
   public:
 
-    ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius );
+    ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
     ~ElementBndBoxTree();
@@ -5900,13 +6323,13 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
    */
   //================================================================================
 
-  ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance)
+  ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
   {
     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
     _elements.reserve( nbElems );
 
-    SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
+    SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
     while ( elemIt->more() )
       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
 
@@ -6038,7 +6461,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
     _refCount = 1;
     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
     while ( nIt->more() )
-      Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
+      Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
     Enlarge( tolerance );
   }
 
@@ -6054,6 +6477,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
 {
   SMESHDS_Mesh*                _mesh;
+  SMDS_ElemIteratorPtr         _meshPartIt;
   ElementBndBoxTree*           _ebbTree;
   SMESH_NodeSearcherImpl*      _nodeSearcher;
   SMDSAbs_ElementType          _elementType;
@@ -6061,8 +6485,8 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
   bool                         _outerFacesFound;
   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
 
-  SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
-    : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
+  SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
+    : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
   ~SMESH_ElementSearcherImpl()
   {
     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
@@ -6138,21 +6562,22 @@ double SMESH_ElementSearcherImpl::getTolerance()
               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
         --complexType;
       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
-
       double elemSize;
       if ( complexType == int( SMDSAbs_Node ))
       {
         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
         elemSize = 1;
         if ( meshInfo.NbNodes() > 2 )
-          elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
+          elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
       }
       else
       {
-        const SMDS_MeshElement* elem =
-          _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
+        SMDS_ElemIteratorPtr elemIt =
+            _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
+        const SMDS_MeshElement* elem = elemIt->next();
         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
-        SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
+        SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
+        elemSize = 0;
         while ( nodeIt->more() )
         {
           double dist = n1.Distance( cast2Node( nodeIt->next() ));
@@ -6185,8 +6610,8 @@ bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           lin
   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
   {
-    GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
-                         SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
+    GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
+                         SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
     anExtCC.Init( lineCurve, edge);
     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
     {
@@ -6246,8 +6671,8 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF
       seamLinks.insert( link );
 
       // link direction within the outerFace
-      gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
-                   SMESH_MeshEditor::TNodeXYZ( link.node2()));
+      gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
+                   SMESH_TNodeXYZ( link.node2()));
       int i1 = outerFace->GetNodeIndex( link.node1() );
       int i2 = outerFace->GetNodeIndex( link.node2() );
       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
@@ -6330,7 +6755,7 @@ FindElementsByPoint(const gp_Pnt&                      point,
     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
     if ( !closeNode ) return foundElements.size();
 
-    if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
+    if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
       return foundElements.size(); // to far from any node
 
     if ( type == SMDSAbs_Node )
@@ -6350,7 +6775,7 @@ FindElementsByPoint(const gp_Pnt&                      point,
     if ( !_ebbTree || _elementType != type )
     {
       if ( _ebbTree ) delete _ebbTree;
-      _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance );
+      _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
     }
     TIDSortedElemSet suspectElems;
     _ebbTree->getElementsNearPoint( point, suspectElems );
@@ -6374,7 +6799,7 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
   if ( !_ebbTree || _elementType != SMDSAbs_Face )
   {
     if ( _ebbTree ) delete _ebbTree;
-    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
+    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
   }
   // Algo: analyse transition of a line starting at the point through mesh boundary;
   // try three lines parallel to axis of the coordinate system and perform rough
@@ -6402,7 +6827,7 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
       // get face plane
       gp_XYZ fNorm;
       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
-      gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
+      gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
 
       // perform intersection
       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
@@ -6598,7 +7023,7 @@ void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&
   if ( !_ebbTree || _elementType != type )
   {
     if ( _ebbTree ) delete _ebbTree;
-    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
+    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
   }
   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
   _ebbTree->getElementsNearLine( line, suspectFaces );
@@ -6616,6 +7041,17 @@ SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
 }
 
+//=======================================================================
+/*!
+ * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
+ */
+//=======================================================================
+
+SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
+{
+  return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
+}
+
 //=======================================================================
 /*!
  * \brief Return true if the point is IN or ON of the element
@@ -6632,16 +7068,21 @@ bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& poi
   // get ordered nodes
 
   vector< gp_XYZ > xyz;
+  vector<const SMDS_MeshNode*> nodeList;
 
   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
-  if ( element->IsQuadratic() )
-    if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
+  if ( element->IsQuadratic() ) {
+    if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
       nodeIt = f->interlacedNodesElemIterator();
-    else if (const SMDS_QuadraticEdge*  e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
+    else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
       nodeIt = e->interlacedNodesElemIterator();
-
+  }
   while ( nodeIt->more() )
-    xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
+    {
+      const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
+      xyz.push_back( SMESH_TNodeXYZ(node) );
+      nodeList.push_back(node);
+    }
 
   int i, nbNodes = element->NbNodes();
 
@@ -6650,6 +7091,7 @@ bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& poi
     // compute face normal
     gp_Vec faceNorm(0,0,0);
     xyz.push_back( xyz.front() );
+    nodeList.push_back( nodeList.front() );
     for ( i = 0; i < nbNodes; ++i )
     {
       gp_Vec edge1( xyz[i+1], xyz[i]);
@@ -6662,9 +7104,7 @@ bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& poi
       // degenerated face: point is out if it is out of all face edges
       for ( i = 0; i < nbNodes; ++i )
       {
-        SMDS_MeshNode n1( xyz[i].X(),   xyz[i].Y(),   xyz[i].Z() );
-        SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
-        SMDS_MeshEdge edge( &n1, &n2 );
+        SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
         if ( !isOut( &edge, point, tol ))
           return false;
       }
@@ -6862,6 +7302,7 @@ int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNode
 
 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 {
+  MESSAGE("MergeNodes");
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
@@ -6878,10 +7319,12 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
     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++ ) {
       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 );
       }
@@ -6898,6 +7341,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
   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 );
 
@@ -6938,8 +7382,11 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
       }
       curNodes[ iCur ] = n;
       bool isUnique = nodeSet.insert( n ).second;
-      if ( isUnique )
+      if ( isUnique ) {
         uniqueNodes[ iUnique++ ] = n;
+        if ( nbRepl && iRepl[ nbRepl-1 ] == iCur )
+          --nbRepl; // n do not stick to a node of the elem
+      }
       iCur++;
     }
 
@@ -6947,6 +7394,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 
     bool isOk = true;
     int nbUniqueNodes = nodeSet.size();
+    //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
       // Polygons and Polyhedral volumes
       if (elem->IsPoly()) {
@@ -6962,10 +7410,9 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
           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 - 1; iface++) {
+            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++) {
@@ -6976,7 +7423,19 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
               if (aShapeId)
                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
             }
-            aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
+
+            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());
@@ -6989,9 +7448,9 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
             rmElemIds.push_back(elem->GetID());
           }
           else {
-            // each face has to be analized in order to check volume validity
-            const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
-              static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
+            // 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();
 
@@ -7019,10 +7478,16 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
               }
 
               if (quantities.size() > 3)
-                aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
-              else
-                rmElemIds.push_back(elem->GetID());
-
+                {
+                  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());
@@ -7033,9 +7498,10 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
         }
 
         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;
@@ -7049,6 +7515,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
             isOk = false;
           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
             isOk = false; // opposite nodes stick
+          //MESSAGE("isOk " << isOk);
         }
         break;
       case 6: ///////////////////////////////////// PENTAHEDRON
@@ -7113,7 +7580,11 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
           //    +---+---+
           //   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];
@@ -7188,14 +7659,20 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
               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]);
+          }
           break;
         }
         //////////////////////////////////// HEXAHEDRON
         isOk = false;
         SMDS_VolumeTool hexa (elem);
         hexa.SetExternalNormal();
-        if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
-          //////////////////////// ---> tetrahedron
+        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 ]] &&
@@ -7205,12 +7682,9 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
               int iOppFace = hexa.GetOppFaceIndex( iFace );
               ind = hexa.GetFaceNodesIndices( iOppFace );
               int nbStick = 0;
-              iUnique = 2; // reverse a tetrahedron bottom
               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
                   nbStick++;
-                else if ( iUnique >= 0 )
-                  uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
               }
               if ( nbStick == 1 ) {
                 // ... and the opposite one - into a triangle.
@@ -7223,6 +7697,45 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
             }
           }
         }
+        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] ))
+          {
+            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;
+                }
+          }
+          break;
+        }
         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
           for ( int iFace = 0; iFace < 6; iFace++ ) {
@@ -7360,6 +7873,10 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
             }
           }
         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
+        else
+        {
+          MESSAGE("MergeNodes() removes hexahedron "<< elem);
+        }
         break;
       } // HEXAHEDRON
 
@@ -7369,11 +7886,12 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 
     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
 
-    if ( isOk ) {
-      if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
+    if ( isOk ) { // the elem remains valid after sticking nodes
+      if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
+      {
         // Change nodes of polyedre
-        const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
-          static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
+        const SMDS_VtkVolume* aPolyedre =
+          dynamic_cast<const SMDS_VtkVolume*>( elem );
         if (aPolyedre) {
           int nbFaces = aPolyedre->NbFaces();
 
@@ -7397,9 +7915,21 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
         }
       }
-      else {
-        // Change regular element or polygon
-        aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
+      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);
+
+        SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
+
+        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 {
@@ -7409,10 +7939,10 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 
   } // loop on elements
 
-  // Remove equal nodes and bad elements
+  // Remove bad elements, then equal nodes (order important)
 
-  Remove( rmNodeIds, true );
   Remove( rmElemIds, false );
+  Remove( rmNodeIds, true );
 
 }
 
@@ -7575,8 +8105,10 @@ SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
   const SMDS_MeshElement* face = 0;
 
   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
+  //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
   {
+    //MESSAGE("in while ( invElemIt->more() && !face )");
     const SMDS_MeshElement* elem = invElemIt->next();
     if (avoidSet.count( elem ))
       continue;
@@ -7595,10 +8127,11 @@ SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
     if ( !face && elem->IsQuadratic())
     {
       // analysis for quadratic elements using all nodes
-      const SMDS_QuadraticFaceOfNodes* F =
-        static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
+      const SMDS_VtkFace* F =
+        dynamic_cast<const SMDS_VtkFace*>(elem);
+      if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
       // use special nodes iterator
-      SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+      SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
       {
@@ -7682,12 +8215,13 @@ bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirst
         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
 
         if(e->IsQuadratic()) {
-          const SMDS_QuadraticFaceOfNodes* F =
-            static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
+          const SMDS_VtkFace* F =
+            dynamic_cast<const SMDS_VtkFace*>(e);
+          if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
           // use special nodes iterator
-          SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+          SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
           while( anIter->more() ) {
-            nodes[ iNode++ ] = anIter->next();
+            nodes[ iNode++ ] = cast2Node(anIter->next());
           }
         }
         else {
@@ -7857,7 +8391,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
     //    links of the free border
     // -------------------------------------------------------------------------
 
-    // 1. Since sewing may brake if there are volumes to split on the side 2,
+    // 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
     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
     TNodeXYZMap nBordXYZ;
@@ -7955,12 +8489,13 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
           if(elem->IsQuadratic()) {
-            const SMDS_QuadraticFaceOfNodes* F =
-              static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
+            const SMDS_VtkFace* F =
+              dynamic_cast<const SMDS_VtkFace*>(elem);
+            if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
             // use special nodes iterator
-            SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+            SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
             while( anIter->more() ) {
-              nodes[ iNode ] = anIter->next();
+              nodes[ iNode ] = cast2Node(anIter->next());
               if ( nodes[ iNode++ ] == prevSideNode )
                 iPrevNode = iNode - 1;
             }
@@ -8274,12 +8809,13 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
 
   if(theFace->IsQuadratic()) {
-    const SMDS_QuadraticFaceOfNodes* F =
-      static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
+    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_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+    SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
     while( anIter->more() ) {
-      const SMDS_MeshNode* n = anIter->next();
+      const SMDS_MeshNode* n = cast2Node(anIter->next());
       if ( n == theBetweenNode1 )
         il1 = iNode;
       else if ( n == theBetweenNode2 )
@@ -8335,12 +8871,13 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
     bool isFLN = false;
 
     if(theFace->IsQuadratic()) {
-      const SMDS_QuadraticFaceOfNodes* F =
-        static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
+      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_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+      SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
       while( anIter->more()  && !isFLN ) {
-        const SMDS_MeshNode* n = anIter->next();
+        const SMDS_MeshNode* n = cast2Node(anIter->next());
         poly_nodes[iNode++] = n;
         if (n == nodes[il1]) {
           isFLN = true;
@@ -8353,7 +8890,7 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
       }
       // add nodes of face starting from last node of link
       while ( anIter->more() ) {
-        poly_nodes[iNode++] = anIter->next();
+        poly_nodes[iNode++] = cast2Node(anIter->next());
       }
     }
     else {
@@ -8396,6 +8933,7 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
     return;
   }
 
+  SMESHDS_Mesh *aMesh = GetMeshDS();
   if( !theFace->IsQuadratic() ) {
 
     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
@@ -8446,7 +8984,6 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
     }
 
     // create new elements
-    SMESHDS_Mesh *aMesh = GetMeshDS();
     int aShapeId = FindShape( theFace );
 
     i1 = 0; i2 = 1;
@@ -8472,8 +9009,16 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
     newNodes[ 1 ] = linkNodes[ i2 ];
     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
     newNodes[ 3 ] = nodes[ i4 ];
-    aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
-  } // end if(!theFace->IsQuadratic())
+    //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] );
+    else
+      newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
+    myLastCreatedElems.Append(newElem);
+    if ( aShapeId && newElem )
+      aMesh->SetMeshElementOnShape( newElem, aShapeId );
+} // end if(!theFace->IsQuadratic())
   else { // theFace is quadratic
     // we have to split theFace on simple triangles and one simple quadrangle
     int tmp = il1/2;
@@ -8500,7 +9045,6 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
     //           n4           n6      n5     n4
 
     // create new elements
-    SMESHDS_Mesh *aMesh = GetMeshDS();
     int aShapeId = FindShape( theFace );
 
     int n1,n2,n3;
@@ -8583,9 +9127,9 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
       if ( aShapeId && newElem )
         aMesh->SetMeshElementOnShape( newElem, aShapeId );
     }
-    // remove old quadratic face
-    aMesh->RemoveElement(theFace);
   }
+  // remove old face
+  aMesh->RemoveElement(theFace);
 }
 
 //=======================================================================
@@ -8677,7 +9221,7 @@ void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode
 //=======================================================================
 /*!
  * \brief Convert elements contained in a submesh to quadratic
- * \retval int - nb of checked elements
+ * \return int - nb of checked elements
  */
 //=======================================================================
 
@@ -8702,7 +9246,7 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
 
     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
-      nbNodeInFaces = static_cast<const SMDS_PolyhedralVolumeOfNodes* >( elem )->GetQuanities();
+      nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
 
     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
 
@@ -8760,6 +9304,8 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
     if( NewElem )
       theSm->AddElement( NewElem );
   }
+//  if (!GetMeshDS()->isCompacted())
+//    GetMeshDS()->compactMesh();
   return nbElem;
 }
 
@@ -8800,6 +9346,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
       if(edge && !edge->IsQuadratic())
       {
         int id = edge->GetID();
+        //MESSAGE("edge->GetID() " << id);
         const SMDS_MeshNode* n1 = edge->GetNode(0);
         const SMDS_MeshNode* n2 = edge->GetNode(1);
 
@@ -8846,7 +9393,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
       int nbNodes = volume->NbNodes();
       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
-        nbNodeInFaces = static_cast<const SMDS_PolyhedralVolumeOfNodes* >(volume)->GetQuanities();
+        nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
 
       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
 
@@ -8876,17 +9423,157 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
     }
   }
 
-  if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
+  if ( !theForce3d )
   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
     aHelper.FixQuadraticElements();
   }
 }
 
+//================================================================================
+/*!
+ * \brief Makes given elements quadratic
+ *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
+ *  \param theElements - elements to make quadratic 
+ */
+//================================================================================
+
+void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
+                                          TIDSortedElemSet& theElements)
+{
+  if ( theElements.empty() ) return;
+
+  // we believe that all theElements are of the same type
+  SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
+  
+  // get all nodes shared by theElements
+  TIDSortedNodeSet allNodes;
+  TIDSortedElemSet::iterator eIt = theElements.begin();
+  for ( ; eIt != theElements.end(); ++eIt )
+    allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
+
+  // complete theElements with elements of lower dim whose all nodes are in allNodes
+
+  TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
+  TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
+  TIDSortedNodeSet::iterator nIt = allNodes.begin();
+  for ( ; nIt != allNodes.end(); ++nIt )
+  {
+    const SMDS_MeshNode* n = *nIt;
+    SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
+    while ( invIt->more() )
+    {
+      const SMDS_MeshElement* e = invIt->next();
+      if ( e->IsQuadratic() )
+      {
+        quadAdjacentElems[ e->GetType() ].insert( e );
+        continue;
+      }
+      if ( e->GetType() >= elemType )
+      {
+        continue; // same type of more complex linear element
+      }
+
+      if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
+        continue; // e is already checked
+
+      // check nodes
+      bool allIn = true;
+      SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
+      while ( nodeIt->more() && allIn )
+        allIn = allNodes.count( cast2Node( nodeIt->next() ));
+      if ( allIn )
+        theElements.insert(e );
+    }
+  }
+
+  SMESH_MesherHelper helper(*myMesh);
+  helper.SetIsQuadratic( true );
+
+  // add links of quadratic adjacent elements to the helper
+
+  if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
+    for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
+          eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
+    {
+      helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
+    }
+  if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
+    for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
+          eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
+    {
+      helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
+    }
+  if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
+    for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
+          eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
+    {
+      helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
+    }
+
+  // make quadratic elements instead of linear ones
+
+  SMESHDS_Mesh* meshDS = GetMeshDS();
+  SMESHDS_SubMesh* smDS = 0;
+  for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
+  {
+    const SMDS_MeshElement* elem = *eIt;
+    if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
+      continue;
+
+    int id = elem->GetID();
+    SMDSAbs_ElementType type = elem->GetType();
+    vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
+
+    if ( !smDS || !smDS->Contains( elem ))
+      smDS = meshDS->MeshElements( elem->getshapeId() );
+    meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
+
+    SMDS_MeshElement * newElem = 0;
+    switch( nodes.size() )
+    {
+    case 4: // cases for most multiple element types go first (for optimization)
+      if ( type == SMDSAbs_Volume )
+        newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
+      else
+        newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
+      break;
+    case 8:
+      newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
+                                 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
+      break;
+    case 3:
+      newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
+      break;
+    case 2:
+      newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
+      break;
+    case 5:
+      newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
+                                 nodes[4], id, theForce3d);
+      break;
+    case 6:
+      newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
+                                 nodes[4], nodes[5], id, theForce3d);
+      break;
+    default:;
+    }
+    ReplaceElemInGroups( elem, newElem, meshDS);
+    if( newElem && smDS )
+      smDS->AddElement( newElem );
+  }
+
+  if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
+  { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
+    helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
+    helper.FixQuadraticElements();
+  }
+}
+
 //=======================================================================
 /*!
  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
- * \retval int - nb of checked elements
+ * \return int - nb of checked elements
  */
 //=======================================================================
 
@@ -8896,7 +9583,6 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
 {
   int nbElem = 0;
   SMESHDS_Mesh* meshDS = GetMeshDS();
-  const bool notFromGroups = false;
 
   while( theItr->more() )
   {
@@ -8904,44 +9590,28 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
     nbElem++;
     if( elem && elem->IsQuadratic())
     {
-      int id = elem->GetID();
-      int nbNodes = elem->NbNodes();
-      vector<const SMDS_MeshNode *> nodes, mediumNodes;
-      nodes.reserve( nbNodes );
-      mediumNodes.reserve( nbNodes );
-
-      for(int i = 0; i < nbNodes; i++)
-      {
-        const SMDS_MeshNode* n = elem->GetNode(i);
-
-        if( elem->IsMediumNode( n ) )
-          mediumNodes.push_back( n );
-        else
-          nodes.push_back( n );
-      }
-      if( nodes.empty() ) continue;
+      int id                    = elem->GetID();
+      int nbCornerNodes         = elem->NbCornerNodes();
       SMDSAbs_ElementType aType = elem->GetType();
 
-      //remove old quadratic element
-      meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
+      vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
 
-      SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
-      ReplaceElemInGroups(elem, NewElem, meshDS);
-      if( theSm && NewElem )
-        theSm->AddElement( NewElem );
+      //remove a quadratic element
+      if ( !theSm || !theSm->Contains( elem ))
+        theSm = meshDS->MeshElements( elem->getshapeId() );
+      meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
 
       // remove medium nodes
-      vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
-      for ( ; nIt != mediumNodes.end(); ++nIt ) {
-        const SMDS_MeshNode* n = *nIt;
-        if ( n->NbInverseElements() == 0 ) {
-          if ( n->GetPosition()->GetShapeId() != theShapeID )
-            meshDS->RemoveFreeNode( n, meshDS->MeshElements
-                                    ( n->GetPosition()->GetShapeId() ));
-          else
-            meshDS->RemoveFreeNode( n, theSm );
-        }
-      }
+      for ( unsigned 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 );
+      ReplaceElemInGroups(elem, newElem, meshDS);
+      if( theSm && newElem )
+        theSm->AddElement( newElem );
     }
   }
   return nbElem;
@@ -8951,7 +9621,8 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
 //function : ConvertFromQuadratic
 //purpose  :
 //=======================================================================
-bool  SMESH_MeshEditor::ConvertFromQuadratic()
+
+bool SMESH_MeshEditor::ConvertFromQuadratic()
 {
   int nbCheckedElems = 0;
   if ( myMesh->HasShapeToMesh() )
@@ -8978,6 +9649,102 @@ bool  SMESH_MeshEditor::ConvertFromQuadratic()
   return true;
 }
 
+namespace
+{
+  //================================================================================
+  /*!
+   * \brief Return true if all medium nodes of the element are in the node set
+   */
+  //================================================================================
+
+  bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
+  {
+    for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
+      if ( !nodeSet.count( elem->GetNode(i) ))
+        return false;
+    return true;
+  }
+}
+
+//================================================================================
+/*!
+ * \brief Makes given elements linear
+ */
+//================================================================================
+
+void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
+{
+  if ( theElements.empty() ) return;
+
+  // collect IDs of medium nodes of theElements; some of these nodes will be removed
+  set<int> mediumNodeIDs;
+  TIDSortedElemSet::iterator eIt = theElements.begin();
+  for ( ; eIt != theElements.end(); ++eIt )
+  {
+    const SMDS_MeshElement* e = *eIt;
+    for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
+      mediumNodeIDs.insert( e->GetNode(i)->GetID() );
+  }
+
+  // replace given elements by linear ones
+  typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
+  SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
+  removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
+
+  // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
+  // except those elements sharing medium nodes of quadratic element whose medium nodes
+  // are not all in mediumNodeIDs
+
+  // get remaining medium nodes
+  TIDSortedNodeSet mediumNodes;
+  set<int>::iterator nIdsIt = mediumNodeIDs.begin();
+  for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
+    if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
+      mediumNodes.insert( mediumNodes.end(), n );
+
+  // find more quadratic elements to convert
+  TIDSortedElemSet moreElemsToConvert;
+  TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
+  for ( ; nIt != mediumNodes.end(); ++nIt )
+  {
+    SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
+    while ( invIt->more() )
+    {
+      const SMDS_MeshElement* e = invIt->next();
+      if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
+      {
+        // find a more complex element including e and
+        // whose medium nodes are not in mediumNodes
+        bool complexFound = false;
+        for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
+        {
+          SMDS_ElemIteratorPtr invIt2 =
+            (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
+          while ( invIt2->more() )
+          {
+            const SMDS_MeshElement* eComplex = invIt2->next();
+            if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
+            {
+              int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
+              if ( nbCommonNodes == e->NbNodes())
+              {
+                complexFound = true;
+                type = SMDSAbs_NbElementTypes; // to quit from the outer loop
+                break;
+              }
+            }
+          }
+        }
+        if ( !complexFound )
+          moreElemsToConvert.insert( e );
+      }
+    }
+  }
+  elemIt = SMDS_ElemIteratorPtr
+    (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
+  removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
+}
+
 //=======================================================================
 //function : SewSideElements
 //purpose  :
@@ -9008,12 +9775,13 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
   // 1. Build set of faces representing each side:
   // =======================================================================
   // a. build set of nodes belonging to faces
-  // b. complete set of faces: find missing fices whose nodes are in set of nodes
+  // b. complete set of faces: find missing faces whose nodes are in set of nodes
   // c. create temporary faces representing side of volumes if correspondent
   //    face does not exist
 
   SMESHDS_Mesh* aMesh = GetMeshDS();
-  SMDS_Mesh aTmpFacesMesh;
+  // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
+  //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
   set<const SMDS_MeshElement*> faceSet1, faceSet2;
   set<const SMDS_MeshElement*> volSet1,  volSet2;
   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
@@ -9023,6 +9791,7 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
   int iSide, iFace, iNode;
 
+  list<const SMDS_MeshElement* > tempFaceList;
   for ( iSide = 0; iSide < 2; iSide++ ) {
     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
@@ -9050,7 +9819,7 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
     // -----------------------------------------------------------
     // 1a. Collect nodes of existing faces
     //     and build set of face nodes in order to detect missing
-    //     faces corresponing to sides of volumes
+    //     faces corresponding to sides of volumes
     // -----------------------------------------------------------
 
     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
@@ -9074,7 +9843,7 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
         volSet->insert( elem );
     }
     // ------------------------------------------------------------------------------
-    // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
+    // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
     // ------------------------------------------------------------------------------
 
     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
@@ -9142,18 +9911,23 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
           if ( !aFreeFace ) {
             // create a temporary face
             if ( nbNodes == 3 ) {
-              aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
+              //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
+              aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
             }
             else if ( nbNodes == 4 ) {
-              aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
+              //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
+              aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
             }
             else {
               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
-              aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
+              //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
+              aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
             }
           }
-          if ( aFreeFace )
+          if ( aFreeFace ) {
             freeFaceList.push_back( aFreeFace );
+            tempFaceList.push_back( aFreeFace );
+          }
 
         } // loop on faces of a volume
 
@@ -9183,7 +9957,7 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
               fIt++;
             }
             else
-              freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
+              freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
           }
           if ( freeFaceList.size() > 1 )
           {
@@ -9267,9 +10041,12 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
 
   if ( faceSet1.size() != faceSet2.size() ) {
     // delete temporary faces: they are in reverseElements of actual nodes
-    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
-    while ( tmpFaceIt->more() )
-      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
+//    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
+//    while ( tmpFaceIt->more() )
+//      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
+//    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
+//    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
+//      aMesh->RemoveElement(*tmpFaceIt);
     MESSAGE("Diff nb of faces");
     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
   }
@@ -9382,10 +10159,11 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
               }
             }
             else { // f->IsQuadratic()
-              const SMDS_QuadraticFaceOfNodes* F =
-                static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
+              const SMDS_VtkFace* F =
+                dynamic_cast<const SMDS_VtkFace*>(f);
+              if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
               // use special nodes iterator
-              SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+              SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
               while ( anIter->more() ) {
                 const SMDS_MeshNode* n =
                   static_cast<const SMDS_MeshNode*>( anIter->next() );
@@ -9425,7 +10203,7 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
     }
 
     // check similarity of elements of the sides
-    if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
+    if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
@@ -9524,9 +10302,12 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
   // ====================================================================
 
   // delete temporary faces: they are in reverseElements of actual nodes
-  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
-  while ( tmpFaceIt->more() )
-    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
+//  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
+//  while ( tmpFaceIt->more() )
+//    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
+//  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
+//  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
+//    aMesh->RemoveElement(*tmpFaceIt);
 
   if ( aResult != SEW_OK)
     return aResult;
@@ -9560,7 +10341,21 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
         //         elemIDsToRemove.push_back( e->GetID() );
         //       else
         if ( nbReplaced )
-          aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
+          {
+            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);
+          }
       }
     }
 
@@ -9579,7 +10374,7 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
  * \param nReplaceMap - output map of corresponding nodes
- * \retval bool  - is a success or not
+ * \return bool  - is a success or not
  */
 //================================================================================
 
@@ -9796,6 +10591,7 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
                                     const SMDS_MeshNode* >& theNodeNodeMap,
                                     const bool theIsDoubleElem )
 {
+  MESSAGE("doubleNodes");
   // iterate on through element and duplicate them (by nodes duplication)
   bool res = false;
   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
@@ -9833,8 +10629,10 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
     if ( theIsDoubleElem )
       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
     else
+      {
+      MESSAGE("ChangeElementNodes");
       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
-
+      }
     res = true;
   }
   return res;
@@ -9854,6 +10652,7 @@ 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();
 
@@ -9926,7 +10725,10 @@ 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;
@@ -9949,7 +10751,7 @@ namespace {
     gp_XYZ centerXYZ (0, 0, 0);
     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
     while (aNodeItr->more())
-      centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
+      centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
 
     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
     theClassifier.Perform(aPnt, theTol);
@@ -10054,6 +10856,655 @@ bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
   return DoubleNodes( theElems, theNodesNot, anAffected );
 }
 
+/*!
+ *  \brief compute an oriented angle between two planes defined by four points.
+ *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
+ *  @param p0 base of the rotation axe
+ *  @param p1 extremity of the rotation axe
+ *  @param g1 belongs to the first plane
+ *  @param g2 belongs to the second plane
+ */
+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);
+}
+
+/*!
+ * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
+ * The list of groups must describe a partition of the mesh volumes.
+ * The nodes of the internal faces at the boundaries of the groups are doubled.
+ * In option, the internal faces are replaced by flat elements.
+ * Triangles are transformed in prisms, and quadrangles in hexahedrons.
+ * The flat elements are stored in groups of volumes.
+ * @param theElems - list of groups of volumes, where a group of volume is a set of
+ * SMDS_MeshElements sorted by Id.
+ * @param createJointElems - if TRUE, create the elements
+ * @return TRUE if operation has been completed successfully, FALSE otherwise
+ */
+bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
+                                                     bool createJointElems)
+{
+  MESSAGE("----------------------------------------------");
+  MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
+  MESSAGE("----------------------------------------------");
+
+  SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
+  meshDS->BuildDownWardConnectivity(true);
+  CHRONO(50);
+  SMDS_UnstructuredGrid *grid = meshDS->getGrid();
+
+  // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
+  //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
+  //     build the list of nodes shared by 2 or more domains, with their domain indexes
+
+  std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
+  std::map<int,int>celldom; // cell vtkId --> domain
+  std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
+  std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
+  faceDomains.clear();
+  celldom.clear();
+  cellDomains.clear();
+  nodeDomains.clear();
+  std::map<int,int> emptyMap;
+  std::set<int> emptySet;
+  emptyMap.clear();
+
+  for (int idom = 0; idom < theElems.size(); idom++)
+    {
+
+      // --- build a map (face to duplicate --> volume to modify)
+      //     with all the faces shared by 2 domains (group of elements)
+      //     and corresponding volume of this domain, for each shared face.
+      //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
+
+      const TIDSortedElemSet& domain = theElems[idom];
+      TIDSortedElemSet::const_iterator elemItr = domain.begin();
+      for (; elemItr != domain.end(); ++elemItr)
+        {
+          SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
+          if (!anElem)
+            continue;
+          int vtkId = anElem->getVtkId();
+          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 (! domain.count(elem)) // neighbor is in another domain : face is shared
+                {
+                  DownIdType face(downIds[n], downTypes[n]);
+                  if (!faceDomains.count(face))
+                    faceDomains[face] = emptyMap; // create an empty entry for face
+                  if (!faceDomains[face].count(idom))
+                    {
+                      faceDomains[face][idom] = vtkId; // volume associated to face in this domain
+                      celldom[vtkId] = idom;
+                    }
+                }
+            }
+        }
+    }
+
+  //MESSAGE("Number of shared faces " << faceDomains.size());
+  std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
+
+  // --- explore the shared faces domain by domain,
+  //     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++)
+    {
+      const TIDSortedElemSet& domain = theElems[idomain];
+      itface = faceDomains.begin();
+      for (; itface != faceDomains.end(); ++itface)
+        {
+          std::map<int, int> domvol = itface->second;
+          if (!domvol.count(idomain))
+            continue;
+          DownIdType face = itface->first;
+          //MESSAGE(" --- face " << face.cellId);
+          std::set<int> oldNodes;
+          oldNodes.clear();
+          grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
+          std::set<int>::iterator itn = oldNodes.begin();
+          for (; itn != oldNodes.end(); ++itn)
+            {
+              int oldId = *itn;
+              //MESSAGE("     node " << oldId);
+              std::set<int> cells;
+              cells.clear();
+              vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
+              for (int i=0; i<l.ncells; i++)
+                {
+                  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 (celldom.count(vtkId))
+                    continue;
+                  cellDomains[aCell][idomain] = vtkId;
+                  celldom[vtkId] = idomain;
+                }
+            }
+        }
+    }
+
+  // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
+  //     for each shared face, get the nodes
+  //     for each node, for each domain of the face, create a clone of the node
+
+  // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
+  //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
+  //     the value is the ordered domain ids. (more than 4 domains not taken into account)
+
+  std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
+  std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
+
+  for (int idomain = 0; idomain < theElems.size(); idomain++)
+    {
+      itface = faceDomains.begin();
+      for (; itface != faceDomains.end(); ++itface)
+        {
+          std::map<int, int> domvol = itface->second;
+          if (!domvol.count(idomain))
+            continue;
+          DownIdType face = itface->first;
+          //MESSAGE(" --- face " << face.cellId);
+          std::set<int> oldNodes;
+          oldNodes.clear();
+          grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
+          bool isMultipleDetected = false;
+          std::set<int>::iterator itn = oldNodes.begin();
+          for (; itn != oldNodes.end(); ++itn)
+            {
+              int oldId = *itn;
+              //MESSAGE("     node " << oldId);
+              if (!nodeDomains.count(oldId))
+                nodeDomains[oldId] = emptyMap; // create an empty entry for node
+              if (nodeDomains[oldId].empty())
+                nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
+              std::map<int, int>::iterator itdom = domvol.begin();
+              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);
+                          isMultipleDetected =true;
+                          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("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
+                    }
+                  if (nodeDomains[oldId].size() >= 3)
+                    {
+                      //MESSAGE("confirm multiple node " << oldId);
+                      isMultipleDetected =true;
+                    }
+                }
+            }
+          if (isMultipleDetected) // 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;
+              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]))
+                    {
+                      vector<int> vn0 = mutipleNodes[nodes[0]];
+                      vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
+                      sort( vn0.begin(), vn0.end() );
+                      sort( vn1.begin(), vn1.end() );
+                      if (vn0 == vn1)
+                        {
+                          //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 < vn0.size(); id++)
+                            {
+                              int idom = vn0[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
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+  // --- iterate on shared faces (volumes to modify, face to extrude)
+  //     get node id's of the face (id SMDS = id VTK)
+  //     create flat element with old and new nodes if requested
+
+  // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
+  //     (domain1 X domain2) = domain1 + MAXINT*domain2
+
+  std::map<int, std::map<long,int> > nodeQuadDomains;
+  std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
+
+  if (createJointElems)
+    {
+      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_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
+                                                             nodeQuadDomains);
+          stringstream grpname;
+          grpname << "j_";
+          if (dom1 < dom2)
+            grpname << dom1 << "_" << dom2;
+          else
+            grpname << dom2 << "_" << dom1;
+          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());
+        }
+    }
+
+  // --- create volumes on multiple domain intersection if requested
+  //     iterate on edgesMultiDomains
+
+  if (createJointElems)
+    {
+      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);
+
+              stringstream grpname;
+              grpname << "mj_";
+              grpname << 0 << "_" << 0;
+              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());
+            }
+          else
+            {
+              //MESSAGE("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.
+  //     associate these faces or edges to their corresponding domain.
+  //     only the first domain found is kept when a face or edge is shared
+
+  std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
+  std::map<int,int> feDom; // vtk id of cell to modify --> id domain
+  faceOrEdgeDom.clear();
+  feDom.clear();
+
+  for (int idomain = 0; idomain < theElems.size(); idomain++)
+    {
+      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 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);
+                    }
+            }
+        }
+    }
+
+  // --- iterate on shared faces (volumes to modify, face to extrude)
+  //     get node id's of the face
+  //     replace old nodes by new nodes in volumes, and update inverse connectivity
+
+  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)
+        {
+          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);
+            }
+        }
+    }
+
+  meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
+  grid->BuildLinks();
+
+  CHRONOSTOP(50);
+  counters::stats();
+  return true;
+}
+
+/*!
+ * \brief Double nodes on some external faces and create flat elements.
+ * Flat elements are mainly used by some types of mechanic calculations.
+ *
+ * Each group of the list must be constituted of faces.
+ * Triangles are transformed in prisms, and quadrangles in hexahedrons.
+ * @param theElems - list of groups of faces, where a group of faces is a set of
+ * SMDS_MeshElements sorted by Id.
+ * @return TRUE if operation has been completed successfully, FALSE otherwise
+ */
+bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
+{
+  MESSAGE("-------------------------------------------------");
+  MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
+  MESSAGE("-------------------------------------------------");
+
+  SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
+
+  // --- For each group of faces
+  //     duplicate the nodes, create a flat element based on the face
+  //     replace the nodes of the faces by their clones
+
+  std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
+  std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
+  clonedNodes.clear();
+  intermediateNodes.clear();
+  std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
+  mapOfJunctionGroups.clear();
+
+  for (int idom = 0; idom < theElems.size(); idom++)
+    {
+      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);
+
+              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];
+
+              if (isMedium)
+                ln3.push_back(clone);
+              else
+                ln1.push_back(clone);
+
+              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);
+                }
+            }
+
+          // --- 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
+
+          aFace->ChangeNodes(&ln[0], ln.size());
+        }
+    }
+  return true;
+}
+
 //================================================================================
 /*!
  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
@@ -10122,17 +11573,24 @@ namespace
  *  \param group - a group to store created boundary elements in
  *  \param targetMesh - a mesh to store created boundary elements in
  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
- *  \param toCopyExistingBondary - if true, not only new but also pre-existing 
+ *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
  *                                boundary elements will be copied into the targetMesh
+ *  \param toAddExistingBondary - if true, not only new but also pre-existing
+ *                                boundary elements will be added into the new group
+ *  \param aroundElements - if true, elements will be created on boundary of given
+ *                          elements else, on boundary of the whole mesh.
+ * \return nb of added boundary elements
  */
 //================================================================================
 
-void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
-                                        Bnd_Dimension           dimension,
-                                        SMESH_Group*            group/*=0*/,
-                                        SMESH_Mesh*             targetMesh/*=0*/,
-                                        bool                    toCopyElements/*=false*/,
-                                        bool                    toCopyExistingBondary/*=false*/)
+int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
+                                       Bnd_Dimension           dimension,
+                                       SMESH_Group*            group/*=0*/,
+                                       SMESH_Mesh*             targetMesh/*=0*/,
+                                       bool                    toCopyElements/*=false*/,
+                                       bool                    toCopyExistingBoundary/*=false*/,
+                                       bool                    toAddExistingBondary/*= false*/,
+                                       bool                    aroundElements/*= false*/)
 {
   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
@@ -10141,13 +11599,20 @@ void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
     throw SALOME_Exception(LOCALIZED("wrong element type"));
 
   if ( !targetMesh )
-    toCopyElements = toCopyExistingBondary = false;
+    toCopyElements = toCopyExistingBoundary = false;
 
   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
+  int nbAddedBnd = 0;
+
+  // editor adding present bnd elements and optionally holding elements to add to the group
+  SMESH_MeshEditor* presentEditor;
+  SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
+  presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
 
   SMDS_VolumeTool vTool;
-  TIDSortedElemSet emptySet, avoidSet;
+  TIDSortedElemSet avoidSet;
+  const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
   int inode;
 
   typedef vector<const SMDS_MeshNode*> TConnectivity;
@@ -10163,18 +11628,22 @@ void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
     const SMDS_MeshElement* elem = eIt->next();
     const int iQuad = elem->IsQuadratic();
 
+    // ------------------------------------------------------------------------------------
     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
+    // ------------------------------------------------------------------------------------
     vector<const SMDS_MeshElement*> presentBndElems;
     vector<TConnectivity>           missingBndElems;
     TConnectivity nodes;
     if ( vTool.Set(elem) ) // 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))
+        if ( !vTool.IsFreeFace(iface, &otherVol) &&
+             ( !aroundElements || elements.count( otherVol )))
           continue;
-        int nbFaceNodes = vTool.NbFaceNodes(iface);
+        const int nbFaceNodes = vTool.NbFaceNodes(iface);
         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
         if ( missType == SMDSAbs_Edge ) // boundary edges
         {
@@ -10203,6 +11672,21 @@ void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
             presentBndElems.push_back( f );
           else
             missingBndElems.push_back( nodes );
+
+          if ( targetMesh != myMesh )
+          {
+            // add 1D elements on face boundary to be added to a new mesh
+            const SMDS_MeshElement* edge;
+            for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
+            {
+              if ( iQuad )
+                edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
+              else
+                edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
+              if ( edge && avoidSet.insert( edge ).second )
+                presentBndElems.push_back( edge );
+            }
+          }
         }
       }
     }
@@ -10215,7 +11699,7 @@ void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
       {
         nodes[0] = elem->GetNode(i);
         nodes[1] = elem->GetNode((i+1)%nbNodes);
-        if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
+        if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
           continue; // not free link
 
         //if ( iQuad )
@@ -10228,40 +11712,60 @@ void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
       }
     }
 
+    // ---------------------------------
     // 2. Add missing boundary elements
+    // ---------------------------------
     if ( targetMesh != myMesh )
       // instead of making a map of nodes in this mesh and targetMesh,
-      // we create nodes with same IDs. We can renumber them later, if needed
+      // we create nodes with same IDs.
       for ( int 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,
+                                                                   missType,
+                                                                   /*noMedium=*/true))
+          continue;
         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
+        ++nbAddedBnd;
       }
     else
       for ( int i = 0; i < missingBndElems.size(); ++i )
       {
-        TConnectivity&  nodes = missingBndElems[i];
+        TConnectivity& nodes = missingBndElems[i];
+        if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
+                                                                   missType,
+                                                                   /*noMedium=*/true))
+          continue;
         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
+        ++nbAddedBnd;
       }
 
+    // ----------------------------------
     // 3. Copy present boundary elements
-    if ( toCopyExistingBondary )
+    // ----------------------------------
+    if ( toCopyExistingBoundary )
       for ( int 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) );
-        tgtEditor.AddElement(nodes, missType, e->IsPoly());
-        // leave only missing elements in tgtEditor.myLastCreatedElems
-        tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
+        presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
+      }
+    else // store present elements to add them to a group
+      for ( int i = 0 ; i < presentBndElems.size(); ++i )
+      {
+        presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
       }
+      
   } // loop on given elements
 
-  // 4. Fill group with missing boundary elements
+  // ---------------------------------------------
+  // 4. Fill group with boundary elements
+  // ---------------------------------------------
   if ( group )
   {
     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
@@ -10269,9 +11773,12 @@ void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
   }
   tgtEditor.myLastCreatedElems.Clear();
+  tgtEditor2.myLastCreatedElems.Clear();
 
+  // -----------------------
   // 5. Copy given elements
-  if ( toCopyElements )
+  // -----------------------
+  if ( toCopyElements && targetMesh != myMesh )
   {
     if (elements.empty())
       eIt = aMesh->elementsIterator(elemType);
@@ -10288,5 +11795,5 @@ void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
       tgtEditor.myLastCreatedElems.Clear();
     }
   }
-  return;
+  return nbAddedBnd;
 }