Salome HOME
A patch by Paul RASCLE for ASTER cluster (64 bits).
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
index b73f854d2e02183bdd38380e856e61733bb49344..6c941745368ac24ba2d12b305d7660518f2aedc8 100644 (file)
@@ -17,7 +17,7 @@
 //  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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 //
 //
 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
 #include "SMDS_FacePosition.hxx"
 #include "SMDS_SpacePosition.hxx"
+#include "SMDS_QuadraticFaceOfNodes.hxx"
 
 #include "SMESHDS_Group.hxx"
 #include "SMESHDS_Mesh.hxx"
 
 #include "SMESH_subMesh.hxx"
 #include "SMESH_ControlsDef.hxx"
+#include "SMESH_MesherHelper.hxx"
+#include "SMESH_OctreeNode.hxx"
 
 #include "utilities.h"
 
 #include <GeomAdaptor_Surface.hxx>
 #include <ElCLib.hxx>
 #include <TColStd_ListOfInteger.hxx>
+#include <TopoDS_Face.hxx>
 
 #include <map>
+#include <set>
+
+#define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
 
 using namespace std;
 using namespace SMESH::Controls;
 
-typedef map<const SMDS_MeshNode*, const SMDS_MeshNode*>              TNodeNodeMap;
 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
 typedef map<const SMDS_MeshNode*, list<const SMDS_MeshNode*> >       TNodeOfNodeListMap;
 typedef TNodeOfNodeListMap::iterator                                 TNodeOfNodeListMapItr;
+//typedef map<const SMDS_MeshNode*, vector<const SMDS_MeshNode*> >     TNodeOfNodeVecMap;
+//typedef TNodeOfNodeVecMap::iterator                                  TNodeOfNodeVecMapItr;
 typedef map<const SMDS_MeshElement*, vector<TNodeOfNodeListMapItr> > TElemOfVecOfNnlmiMap;
+//typedef map<const SMDS_MeshElement*, vector<TNodeOfNodeVecMapItr> >  TElemOfVecOfMapNodesMap;
+
+struct TNodeXYZ : public gp_XYZ {
+  TNodeXYZ( const SMDS_MeshNode* n ):gp_XYZ( n->X(), n->Y(), n->Z() ) {}
+};
+
+typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
+
+/*!
+ * \brief A sorted pair of nodes
+ */
+struct TLink: public NLink
+{
+  TLink(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2 ):NLink( n1, n2 )
+  { if ( n1->GetID() < n2->GetID() ) std::swap( first, second ); }
+  TLink(const NLink& link ):NLink( link )
+  { if ( first->GetID() < second->GetID() ) std::swap( first, second ); }
+};
 
 //=======================================================================
 //function : SMESH_MeshEditor
@@ -87,6 +113,137 @@ myMesh( theMesh )
 {
 }
 
+//=======================================================================
+/*!
+ * \brief Add element
+ */
+//=======================================================================
+
+SMDS_MeshElement*
+SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
+                             const SMDSAbs_ElementType            type,
+                             const bool                           isPoly,
+                             const int                            ID)
+{
+  SMDS_MeshElement* e = 0;
+  int nbnode = node.size();
+  SMESHDS_Mesh* mesh = GetMeshDS();
+  switch ( type ) {
+  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] );
+    } else {
+      if ( ID ) 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] );
+    }
+  }
+  return e;
+}
+
+//=======================================================================
+/*!
+ * \brief Add element
+ */
+//=======================================================================
+
+SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
+                                               const SMDSAbs_ElementType type,
+                                               const bool                isPoly,
+                                               const int                 ID)
+{
+  vector<const SMDS_MeshNode*> nodes;
+  nodes.reserve( nodeIDs.size() );
+  vector<int>::const_iterator id = nodeIDs.begin();
+  while ( id != nodeIDs.end() ) {
+    if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
+      nodes.push_back( node );
+    else
+      return 0;
+  }
+  return AddElement( nodes, type, isPoly, ID );
+}
+
 //=======================================================================
 //function : Remove
 //purpose  : Remove a node or an element.
@@ -96,13 +253,14 @@ myMesh( theMesh )
 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
                                const bool         isNodes )
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
 
   SMESHDS_Mesh* aMesh = GetMeshDS();
   set< SMESH_subMesh *> smmap;
 
   list<int>::const_iterator it = theIDs.begin();
-  for ( ; it != theIDs.end(); it++ )
-  {
+  for ( ; it != theIDs.end(); it++ ) {
     const SMDS_MeshElement * elem;
     if ( isNodes )
       elem = aMesh->FindNode( *it );
@@ -113,16 +271,12 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
 
     // Find sub-meshes to notify about modification
     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
-    while ( nodeIt->more() )
-    {
+    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();
-        if ( aShapeID ) {
-          TopoDS_Shape aShape = aMesh->IndexToShape( aShapeID );
-          SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShape );
-          if ( sm )
+        if ( int aShapeID = aPosition->GetShapeId() ) {
+          if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
             smmap.insert( sm );
         }
       }
@@ -141,6 +295,11 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
   }
+
+  // Check if the whole mesh becomes empty
+  if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
+    sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
+
   return true;
 }
 
@@ -152,12 +311,14 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
 
 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   SMESHDS_Mesh * aMesh = GetMeshDS();
   if ( aMesh->ShapeToMesh().IsNull() )
     return 0;
 
-  if ( theElem->GetType() == SMDSAbs_Node )
-  {
+  if ( theElem->GetType() == SMDSAbs_Node ) {
     const SMDS_PositionPtr& aPosition =
       static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
     if ( aPosition.get() )
@@ -168,25 +329,22 @@ int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
 
   TopoDS_Shape aShape; // the shape a node is on
   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
-  while ( nodeIt->more() )
-  {
+  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 );
-        }
+      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 );
       }
+    }
   }
 
   // None of nodes is on a proper shape,
@@ -196,17 +354,106 @@ int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
     return 0;
   }
   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() );
+  for ( ; ancIt.More(); ancIt.Next() ) {
+    SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
+    if ( sm && sm->Contains( theElem ))
+      return aMesh->ShapeToIndex( ancIt.Value() );
   }
 
   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
   return 0;
 }
 
+//=======================================================================
+//function : IsMedium
+//purpose  :
+//=======================================================================
+
+bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
+                                const SMDSAbs_ElementType typeToCheck)
+{
+  bool isMedium = false;
+  SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
+  while (it->more() && !isMedium ) {
+    const SMDS_MeshElement* elem = it->next();
+    isMedium = elem->IsMediumNode(node);
+  }
+  return isMedium;
+}
+
+//=======================================================================
+//function : ShiftNodesQuadTria
+//purpose  : auxilary
+//           Shift nodes in the array corresponded to quadratic triangle
+//           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
+//=======================================================================
+static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
+{
+  const SMDS_MeshNode* nd1 = aNodes[0];
+  aNodes[0] = aNodes[1];
+  aNodes[1] = aNodes[2];
+  aNodes[2] = nd1;
+  const SMDS_MeshNode* nd2 = aNodes[3];
+  aNodes[3] = aNodes[4];
+  aNodes[4] = aNodes[5];
+  aNodes[5] = nd2;
+}
+
+//=======================================================================
+//function : GetNodesFromTwoTria
+//purpose  : auxilary
+//           Shift nodes in the array corresponded to quadratic triangle
+//           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
+//=======================================================================
+static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
+                                const SMDS_MeshElement * theTria2,
+                                const SMDS_MeshNode* N1[],
+                                const SMDS_MeshNode* N2[])
+{
+  SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
+  int i=0;
+  while(i<6) {
+    N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
+    i++;
+  }
+  if(it->more()) return false;
+  it = theTria2->nodesIterator();
+  i=0;
+  while(i<6) {
+    N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
+    i++;
+  }
+  if(it->more()) return false;
+
+  int sames[3] = {-1,-1,-1};
+  int nbsames = 0;
+  int j;
+  for(i=0; i<3; i++) {
+    for(j=0; j<3; j++) {
+      if(N1[i]==N2[j]) {
+        sames[i] = j;
+        nbsames++;
+        break;
+      }
+    }
+  }
+  if(nbsames!=2) return false;
+  if(sames[0]>-1) {
+    ShiftNodesQuadTria(N1);
+    if(sames[1]>-1) {
+      ShiftNodesQuadTria(N1);
+    }
+  }
+  i = sames[0] + sames[1] + sames[2];
+  for(; i<2; i++) {
+    ShiftNodesQuadTria(N2);
+  }
+  // now we receive following N1 and N2 (using numeration as above image)
+  // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
+  // i.e. first nodes from both arrays determ new diagonal
+  return true;
+}
+
 //=======================================================================
 //function : InverseDiag
 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
@@ -217,73 +464,121 @@ int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
                                     const SMDS_MeshElement * theTria2 )
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   if (!theTria1 || !theTria2)
     return false;
+
   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
-  if (!F1) return false;
   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
-  if (!F2) return false;
+  if (F1 && F2) {
 
-  //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
-  //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
-  //    |/ |                                         | \|
-  //  B +--+ 2                                     B +--+ 2
+    //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
+    //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
+    //    |/ |                                         | \|
+    //  B +--+ 2                                     B +--+ 2
 
-  // put nodes in array and find out indices of the same ones
-  const SMDS_MeshNode* aNodes [6];
-  int sameInd [] = { 0, 0, 0, 0, 0, 0 };
-  int i = 0;
-  SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
-  while ( it->more() )
-  {
-    aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
-
-    if ( i > 2 ) // theTria2
-      // find same node of theTria1
-      for ( int j = 0; j < 3; j++ )
-        if ( aNodes[ i ] == aNodes[ j ]) {
-          sameInd[ j ] = i;
-          sameInd[ i ] = j;
-          break;
-        }
-    // next
-    i++;
-    if ( i == 3 ) {
-      if ( it->more() )
-        return false; // theTria1 is not a triangle
-      it = theTria2->nodesIterator();
+    // put nodes in array and find out indices of the same ones
+    const SMDS_MeshNode* aNodes [6];
+    int sameInd [] = { 0, 0, 0, 0, 0, 0 };
+    int i = 0;
+    SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
+    while ( it->more() ) {
+      aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
+
+      if ( i > 2 ) // theTria2
+        // find same node of theTria1
+        for ( int j = 0; j < 3; j++ )
+          if ( aNodes[ i ] == aNodes[ j ]) {
+            sameInd[ j ] = i;
+            sameInd[ i ] = j;
+            break;
+          }
+      // next
+      i++;
+      if ( i == 3 ) {
+        if ( it->more() )
+          return false; // theTria1 is not a triangle
+        it = theTria2->nodesIterator();
+      }
+      if ( i == 6 && it->more() )
+        return false; // theTria2 is not a triangle
     }
-    if ( i == 6 && it->more() )
-      return false; // theTria2 is not a triangle
-  }
 
-  // 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 ( i < 3 ) i1 = i;
-      else         i2 = i;
-    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 ] )
-    return false;
+    // 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 ( i < 3 ) i1 = i;
+        else         i2 = i;
+      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 ] )
+      return false;
 
+    // theTria1: A->2
+    aNodes[ iA ] = aNodes[ i2 ];
+    // theTria2: B->1
+    aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
 
-  // theTria1: A->2
-  aNodes[ iA ] = aNodes[ i2 ];
-  // theTria2: B->1
-  aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
+    //MESSAGE( theTria1 << theTria2 );
 
-  //MESSAGE( theTria1 << theTria2 );
+    GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
+    GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
 
-  GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
-  GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
+    //MESSAGE( theTria1 << theTria2 );
+
+    return true;
 
-  //MESSAGE( theTria1 << theTria2 );
+  } // 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;
+
+  //       5
+  //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
+  //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
+  //    |   / |
+  //  7 +  +  + 6
+  //    | /9  |
+  //    |/    |
+  //  4 +--+--+ 3
+  //       8
+
+  const SMDS_MeshNode* N1 [6];
+  const SMDS_MeshNode* N2 [6];
+  if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
+    return false;
+  // now we receive following N1 and N2 (using numeration as above image)
+  // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
+  // i.e. first nodes from both arrays determ new diagonal
+
+  const SMDS_MeshNode* N1new [6];
+  const SMDS_MeshNode* N2new [6];
+  N1new[0] = N1[0];
+  N1new[1] = N2[0];
+  N1new[2] = N2[1];
+  N1new[3] = N1[4];
+  N1new[4] = N2[3];
+  N1new[5] = N1[5];
+  N2new[0] = N1[0];
+  N2new[1] = N1[1];
+  N2new[2] = N2[0];
+  N2new[3] = N1[3];
+  N2new[4] = N2[5];
+  N2new[5] = N1[4];
+  // replaces nodes in faces
+  GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
+  GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
 
   return true;
 }
@@ -303,21 +598,28 @@ static bool findTriangles(const SMDS_MeshNode *    theNode1,
   theTria1 = theTria2 = 0;
 
   set< const SMDS_MeshElement* > emap;
-  SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator();
+  SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
   while (it->more()) {
     const SMDS_MeshElement* elem = it->next();
-    if ( elem->GetType() == SMDSAbs_Face && elem->NbNodes() == 3 )
+    if ( elem->NbNodes() == 3 )
       emap.insert( elem );
   }
-  it = theNode2->GetInverseElementIterator();
+  it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
   while (it->more()) {
     const SMDS_MeshElement* elem = it->next();
-    if ( elem->GetType() == SMDSAbs_Face &&
-         emap.find( elem ) != emap.end() )
+    if ( emap.find( elem ) != emap.end() )
       if ( theTria1 ) {
-        theTria2 = elem;
+        // theTria1 must be element with minimum ID
+        if( theTria1->GetID() < elem->GetID() ) {
+          theTria2 = elem;
+        }
+        else {
+          theTria2 = theTria1;
+          theTria1 = elem;
+        }
         break;
-      } else {
+      }
+      else {
         theTria1 = elem;
       }
   }
@@ -334,6 +636,9 @@ static bool findTriangles(const SMDS_MeshNode *    theNode1,
 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
                                     const SMDS_MeshNode * theNode2)
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   MESSAGE( "::InverseDiag()" );
 
   const SMDS_MeshElement *tr1, *tr2;
@@ -341,55 +646,65 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
     return false;
 
   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
-  if (!F1) return false;
+  //if (!F1) return false;
   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
-  if (!F2) return false;
-
-  //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
-  //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
-  //    |/ |                                    | \|
-  //  B +--+ 2                                B +--+ 2
-
-  // put nodes in array
-  // and find indices of 1,2 and of A in tr1 and of B in tr2
-  int i, iA1 = 0, i1 = 0;
-  const SMDS_MeshNode* aNodes1 [3];
-  SMDS_ElemIteratorPtr it;
-  for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
-    aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
-    if ( aNodes1[ i ] == theNode1 )
-      iA1 = i; // node A in tr1
-    else if ( aNodes1[ i ] != theNode2 )
-      i1 = i;  // node 1
-  }
-  int iB2 = 0, i2 = 0;
-  const SMDS_MeshNode* aNodes2 [3];
-  for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
-    aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
-    if ( aNodes2[ i ] == theNode2 )
-      iB2 = i; // node B in tr2
-    else if ( aNodes2[ i ] != theNode1 )
-      i2 = i;  // node 2
-  }
+  //if (!F2) return false;
+  if (F1 && F2) {
+
+    //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
+    //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
+    //    |/ |                                    | \|
+    //  B +--+ 2                                B +--+ 2
+
+    // put nodes in array
+    // and find indices of 1,2 and of A in tr1 and of B in tr2
+    int i, iA1 = 0, i1 = 0;
+    const SMDS_MeshNode* aNodes1 [3];
+    SMDS_ElemIteratorPtr it;
+    for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
+      aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
+      if ( aNodes1[ i ] == theNode1 )
+        iA1 = i; // node A in tr1
+      else if ( aNodes1[ i ] != theNode2 )
+        i1 = i;  // node 1
+    }
+    int iB2 = 0, i2 = 0;
+    const SMDS_MeshNode* aNodes2 [3];
+    for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
+      aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
+      if ( aNodes2[ i ] == theNode2 )
+        iB2 = i; // node B in tr2
+      else if ( aNodes2[ i ] != theNode1 )
+        i2 = i;  // node 2
+    }
 
-  // nodes 1 and 2 should not be the same
-  if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
-    return false;
+    // nodes 1 and 2 should not be the same
+    if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
+      return false;
 
-  // tr1: A->2
-  aNodes1[ iA1 ] = aNodes2[ i2 ];
-  // tr2: B->1
-  aNodes2[ iB2 ] = aNodes1[ i1 ];
+    // tr1: A->2
+    aNodes1[ iA1 ] = aNodes2[ i2 ];
+    // tr2: B->1
+    aNodes2[ iB2 ] = aNodes1[ i1 ];
 
-  //MESSAGE( tr1 << tr2 );
+    //MESSAGE( tr1 << tr2 );
 
-  GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
-  GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
+    GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
+    GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
 
-  //MESSAGE( tr1 << tr2 );
+    //MESSAGE( tr1 << tr2 );
 
-  return true;
+    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);
 }
 
 //=======================================================================
@@ -405,12 +720,15 @@ bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
                         const SMDS_MeshElement * tr1,
                         const SMDS_MeshElement * tr2 )
 {
+  if( tr1->NbNodes() != tr2->NbNodes() )
+    return false;
   // find the 4-th node to insert into tr1
   const SMDS_MeshNode* n4 = 0;
   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
-  while ( !n4 && it->more() )
-  {
-    const SMDS_MeshNode * n = static_cast<const SMDS_MeshNode*>( it->next() );
+  int i=0;
+  while ( !n4 && i<3 ) {
+    const SMDS_MeshNode * n = cast2Node( it->next() );
+    i++;
     bool isDiag = ( n == theNode1 || n == theNode2 );
     if ( !isDiag )
       n4 = n;
@@ -418,19 +736,18 @@ bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
   // Make an array of nodes to be in a quadrangle
   int iNode = 0, iFirstDiag = -1;
   it = tr1->nodesIterator();
-  while ( it->more() )
-  {
-    const SMDS_MeshNode * n = static_cast<const SMDS_MeshNode*>( it->next() );
+  i=0;
+  while ( i<3 ) {
+    const SMDS_MeshNode * n = cast2Node( it->next() );
+    i++;
     bool isDiag = ( n == theNode1 || n == theNode2 );
-    if ( isDiag )
-    {
+    if ( isDiag ) {
       if ( iFirstDiag < 0 )
         iFirstDiag = iNode;
       else if ( iNode - iFirstDiag == 1 )
         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
     }
-    else if ( n == n4 )
-    {
+    else if ( n == n4 ) {
       return false; // tr1 and tr2 should not have all the same nodes
     }
     theQuadNodes[ iNode++ ] = n;
@@ -451,6 +768,9 @@ bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
                                    const SMDS_MeshNode * theNode2)
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   MESSAGE( "::DeleteDiag()" );
 
   const SMDS_MeshElement *tr1, *tr2;
@@ -458,20 +778,68 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
     return false;
 
   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
-  if (!F1) return false;
+  //if (!F1) return false;
   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
-  if (!F2) return false;
+  //if (!F2) return false;
+  if (F1 && F2) {
 
-  const SMDS_MeshNode* aNodes [ 4 ];
-  if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
-    return false;
+    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 );
 
-  //MESSAGE( endl << tr1 << tr2 );
+    return true;
+  }
 
-  GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
+  // 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;
+
+  //       5
+  //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
+  //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
+  //    |   / |
+  //  7 +  +  + 6
+  //    | /9  |
+  //    |/    |
+  //  4 +--+--+ 3
+  //       8
+
+  const SMDS_MeshNode* N1 [6];
+  const SMDS_MeshNode* N2 [6];
+  if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
+    return false;
+  // now we receive following N1 and N2 (using numeration as above image)
+  // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
+  // i.e. first nodes from both arrays determ new diagonal
+
+  const SMDS_MeshNode* aNodes[8];
+  aNodes[0] = N1[0];
+  aNodes[1] = N1[1];
+  aNodes[2] = N2[0];
+  aNodes[3] = N2[1];
+  aNodes[4] = N1[3];
+  aNodes[5] = N2[5];
+  aNodes[6] = N2[3];
+  aNodes[7] = N1[5];
+
+  GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
+  myLastCreatedElems.Append(tr1);
   GetMeshDS()->RemoveElement( tr2 );
 
-  //MESSAGE( endl << tr1 );
+  // remove middle node (9)
+  GetMeshDS()->RemoveNode( N1[4] );
 
   return true;
 }
@@ -483,6 +851,9 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
 
 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   if (!theElem)
     return false;
   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
@@ -492,16 +863,39 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
   switch ( theElem->GetType() ) {
 
   case SMDSAbs_Edge:
-  case SMDSAbs_Face:
-  {
-    int i = theElem->NbNodes();
-    vector<const SMDS_MeshNode*> aNodes( i );
-    while ( it->more() )
-      aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
-    return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
+  case SMDSAbs_Face: {
+    if(!theElem->IsQuadratic()) {
+      int i = theElem->NbNodes();
+      vector<const SMDS_MeshNode*> aNodes( i );
+      while ( it->more() )
+        aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
+      return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
+    }
+    else {
+      // quadratic elements
+      if(theElem->GetType()==SMDSAbs_Edge) {
+        vector<const SMDS_MeshNode*> aNodes(3);
+        aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
+        aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
+        aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
+        return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
+      }
+      else {
+        int nbn = theElem->NbNodes();
+        vector<const SMDS_MeshNode*> aNodes(nbn);
+        aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
+        int i=1;
+        for(; i<nbn/2; i++) {
+          aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
+        }
+        for(i=0; i<nbn/2; i++) {
+          aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
+        }
+        return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
+      }
+    }
   }
-  case SMDSAbs_Volume:
-  {
+  case SMDSAbs_Volume: {
     if (theElem->IsPoly()) {
       const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
         static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
@@ -527,7 +921,8 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
 
       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
 
-    } else {
+    }
+    else {
       SMDS_VolumeTool vTool;
       if ( !vTool.Set( theElem ))
         return false;
@@ -562,9 +957,12 @@ static double getBadRate (const SMDS_MeshElement*               theElem,
 //           theCrit is used to select a diagonal to cut
 //=======================================================================
 
-bool SMESH_MeshEditor::QuadToTri (set<const SMDS_MeshElement*> &       theElems,
+bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
                                   SMESH::Controls::NumericalFunctorPtr theCrit)
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   MESSAGE( "::QuadToTri()" );
 
   if ( !theCrit.get() )
@@ -572,15 +970,19 @@ bool SMESH_MeshEditor::QuadToTri (set<const SMDS_MeshElement*> &       theElems,
 
   SMESHDS_Mesh * aMesh = GetMeshDS();
 
-  set< const SMDS_MeshElement * >::iterator itElem;
-  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
-  {
-    const SMDS_MeshElement* elem = (*itElem);
-    if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() != 4 )
+  Handle(Geom_Surface) surface;
+  SMESH_MesherHelper   helper( *GetMesh() );
+
+  TIDSortedElemSet::iterator itElem;
+  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+    const SMDS_MeshElement* elem = *itElem;
+    if ( !elem || elem->GetType() != SMDSAbs_Face )
+      continue;
+    if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
       continue;
 
     // retrieve element nodes
-    const SMDS_MeshNode* aNodes [4];
+    const SMDS_MeshNode* aNodes [8];
     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
     int i = 0;
     while ( itN->more() )
@@ -597,30 +999,107 @@ bool SMESH_MeshEditor::QuadToTri (set<const SMDS_MeshElement*> &       theElems,
     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
 
     int aShapeId = FindShape( elem );
-    //MESSAGE( "aBadRate1 = " << aBadRate1 << "; aBadRate2 = " << aBadRate2
-      //      << " ShapeID = " << aShapeId << endl << elem );
+    const SMDS_MeshElement* newElem = 0;
+
+    if( !elem->IsQuadratic() ) {
 
-    if ( aBadRate1 <= aBadRate2 ) {
-      // tr1 + tr2 is better
-      aMesh->ChangeElementNodes( elem, aNodes, 3 );
-      //MESSAGE( endl << elem );
+      // split liner quadrangle
 
-      elem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
+      if ( aBadRate1 <= aBadRate2 ) {
+        // tr1 + tr2 is better
+        aMesh->ChangeElementNodes( elem, aNodes, 3 );
+        newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
+      }
+      else {
+        // tr3 + tr4 is better
+        aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
+        newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
+      }
     }
     else {
-      // tr3 + tr4 is better
-      aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
-      //MESSAGE( endl << elem );
 
-      elem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
-    }
-    //MESSAGE( endl << elem );
+      // split quadratic quadrangle
+
+      // get surface elem is on
+      if ( aShapeId != helper.GetSubShapeID() ) {
+        surface.Nullify();
+        TopoDS_Shape shape;
+        if ( aShapeId > 0 )
+          shape = aMesh->IndexToShape( aShapeId );
+        if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
+          TopoDS_Face face = TopoDS::Face( shape );
+          surface = BRep_Tool::Surface( face );
+          if ( !surface.IsNull() )
+            helper.SetSubShape( shape );
+        }
+      }
+      // get elem nodes
+      const SMDS_MeshNode* aNodes [8];
+      const SMDS_MeshNode* inFaceNode = 0;
+      SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+      int i = 0;
+      while ( itN->more() ) {
+        aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
+        if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
+             aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
+        {
+          inFaceNode = aNodes[ i-1 ];
+        }
+      }
+      // find middle point for (0,1,2,3)
+      // and create a node in this point;
+      gp_XYZ p( 0,0,0 );
+      if ( surface.IsNull() ) {
+        for(i=0; i<4; i++)
+          p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
+        p /= 4;
+      }
+      else {
+        TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
+        gp_XY uv( 0,0 );
+        for(i=0; i<4; i++)
+          uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
+        uv /= 4.;
+        p = surface->Value( uv.X(), uv.Y() ).XYZ();
+      }
+      const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
+      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 );
+      }
+      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 );
+      }
+      aMesh->ChangeElementNodes( elem, N, 6 );
+
+    } // quadratic case
+
+    // care of a new element
+
+    myLastCreatedElems.Append(newElem);
+    AddToSameGroups( newElem, elem, aMesh );
 
     // put a new triangle on the same shape
     if ( aShapeId )
-      aMesh->SetMeshElementOnShape( elem, aShapeId );
+      aMesh->SetMeshElementOnShape( newElem, aShapeId );
   }
-
   return true;
 }
 
@@ -631,33 +1110,42 @@ bool SMESH_MeshEditor::QuadToTri (set<const SMDS_MeshElement*> &       theElems,
 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
                                  SMESH::Controls::NumericalFunctorPtr theCrit)
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   if (!theCrit.get())
     return -1;
 
-  if (!theQuad || theQuad->GetType() != SMDSAbs_Face || theQuad->NbNodes() != 4)
+  if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
     return -1;
 
-  // retrieve element nodes
-  const SMDS_MeshNode* aNodes [4];
-  SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
-  int i = 0;
-  while (itN->more())
-    aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
+  if( theQuad->NbNodes()==4 ||
+      (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
 
-  // compare two sets of possible triangles
-  double aBadRate1, aBadRate2; // to what extent a set is bad
-  SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
-  SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
-  aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
+    // retrieve element nodes
+    const SMDS_MeshNode* aNodes [4];
+    SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
+    int i = 0;
+    //while (itN->more())
+    while (i<4) {
+      aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
+    }
+    // compare two sets of possible triangles
+    double aBadRate1, aBadRate2; // to what extent a set is bad
+    SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
+    SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
+    aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
 
-  SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
-  SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
-  aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
+    SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
+    SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
+    aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
 
-  if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
-    return 1; // diagonal 1-3
+    if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
+      return 1; // diagonal 1-3
 
-  return 2; // diagonal 2-4
+    return 2; // diagonal 2-4
+  }
+  return -1;
 }
 
 //=======================================================================
@@ -678,52 +1166,161 @@ void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
   }
 }
 
+
+//=======================================================================
+//function : RemoveElemFromGroups
+//purpose  : Remove removeelem to the groups the elemInGroups belongs to
+//=======================================================================
+void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
+                                             SMESHDS_Mesh *          aMesh)
+{
+  const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
+  if (!groups.empty())
+  {
+    set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
+    for (; GrIt != groups.end(); GrIt++)
+    {
+      SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
+      if (!grp || grp->IsEmpty()) continue;
+      grp->SMDSGroup().Remove(removeelem);
+    }
+  }
+}
+
+
 //=======================================================================
 //function : QuadToTri
 //purpose  : Cut quadrangles into triangles.
 //           theCrit is used to select a diagonal to cut
 //=======================================================================
 
-bool SMESH_MeshEditor::QuadToTri (std::set<const SMDS_MeshElement*> & theElems,
-                                  const bool                          the13Diag)
+bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
+                                  const bool         the13Diag)
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   MESSAGE( "::QuadToTri()" );
 
   SMESHDS_Mesh * aMesh = GetMeshDS();
 
-  set< const SMDS_MeshElement * >::iterator itElem;
-  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
-  {
-    const SMDS_MeshElement* elem = (*itElem);
-    if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() != 4 )
+  Handle(Geom_Surface) surface;
+  SMESH_MesherHelper   helper( *GetMesh() );
+
+  TIDSortedElemSet::iterator itElem;
+  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+    const SMDS_MeshElement* elem = *itElem;
+    if ( !elem || elem->GetType() != SMDSAbs_Face )
       continue;
+    bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
+    if(!isquad) continue;
 
-    // retrieve element nodes
-    const SMDS_MeshNode* aNodes [4];
-    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-    int i = 0;
-    while ( itN->more() )
-      aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
+    if(elem->NbNodes()==4) {
+      // retrieve element nodes
+      const SMDS_MeshNode* aNodes [4];
+      SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+      int i = 0;
+      while ( itN->more() )
+        aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
 
-    int aShapeId = FindShape( elem );
-    const SMDS_MeshElement* newElem = 0;
-    if ( the13Diag )
-    {
-      aMesh->ChangeElementNodes( elem, aNodes, 3 );
-      newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
-    }
-    else
-    {
-      aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
-      newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
+      int aShapeId = FindShape( elem );
+      const SMDS_MeshElement* newElem = 0;
+      if ( the13Diag ) {
+        aMesh->ChangeElementNodes( elem, aNodes, 3 );
+        newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
+      }
+      else {
+        aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
+        newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
+      }
+      myLastCreatedElems.Append(newElem);
+      // put a new triangle on the same shape and add to the same groups
+      if ( aShapeId )
+        aMesh->SetMeshElementOnShape( newElem, aShapeId );
+      AddToSameGroups( newElem, elem, aMesh );
     }
 
-    // put a new triangle on the same shape and add to the same groups
+    // Quadratic quadrangle
 
-    if ( aShapeId )
-      aMesh->SetMeshElementOnShape( newElem, aShapeId );
+    if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
 
-    AddToSameGroups( newElem, elem, aMesh );
+      // get surface elem is on
+      int aShapeId = FindShape( elem );
+      if ( aShapeId != helper.GetSubShapeID() ) {
+        surface.Nullify();
+        TopoDS_Shape shape;
+        if ( aShapeId > 0 )
+          shape = aMesh->IndexToShape( aShapeId );
+        if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
+          TopoDS_Face face = TopoDS::Face( shape );
+          surface = BRep_Tool::Surface( face );
+          if ( !surface.IsNull() )
+            helper.SetSubShape( shape );
+        }
+      }
+
+      const SMDS_MeshNode* aNodes [8];
+      const SMDS_MeshNode* inFaceNode = 0;
+      SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+      int i = 0;
+      while ( itN->more() ) {
+        aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
+        if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
+             aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
+        {
+          inFaceNode = aNodes[ i-1 ];
+        }
+      }
+
+      // find middle point for (0,1,2,3)
+      // and create a node in this point;
+      gp_XYZ p( 0,0,0 );
+      if ( surface.IsNull() ) {
+        for(i=0; i<4; i++)
+          p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
+        p /= 4;
+      }
+      else {
+        TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
+        gp_XY uv( 0,0 );
+        for(i=0; i<4; i++)
+          uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
+        uv /= 4.;
+        p = surface->Value( uv.X(), uv.Y() ).XYZ();
+      }
+      const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
+      myLastCreatedNodes.Append(newN);
+
+      // create a new element
+      const SMDS_MeshElement* newElem = 0;
+      const SMDS_MeshNode* N[6];
+      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 );
+      }
+      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 );
+      }
+      myLastCreatedElems.Append(newElem);
+      aMesh->ChangeElementNodes( elem, N, 6 );
+      // put a new triangle on the same shape and add to the same groups
+      if ( aShapeId )
+        aMesh->SetMeshElementOnShape( newElem, aShapeId );
+      AddToSameGroups( newElem, elem, aMesh );
+    }
   }
 
   return true;
@@ -746,18 +1343,24 @@ double getAngle(const SMDS_MeshElement * tr1,
   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
     return angle;
-  gp_Vec N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
+  gp_Vec N1,N2;
+  if(!tr1->IsQuadratic())
+    N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
+  else
+    N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
   if ( N1.SquareMagnitude() <= gp::Resolution() )
     return angle;
-  gp_Vec N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
+  if(!tr2->IsQuadratic())
+    N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
+  else
+    N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
   if ( N2.SquareMagnitude() <= gp::Resolution() )
     return angle;
 
   // find the first diagonal node n1 in the triangles:
   // take in account a diagonal link orientation
   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
-  for ( int t = 0; t < 2; t++ )
-  {
+  for ( int t = 0; t < 2; t++ ) {
     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
     int i = 0, iDiag = -1;
     while ( it->more()) {
@@ -787,7 +1390,6 @@ double getAngle(const SMDS_MeshElement * tr1,
 // class generating a unique ID for a pair of nodes
 // and able to return nodes by that ID
 // =================================================
-
 class LinkID_Gen {
  public:
 
@@ -818,6 +1420,7 @@ class LinkID_Gen {
   long                myMaxID;
 };
 
+
 //=======================================================================
 //function : TriToQuad
 //purpose  : Fuse neighbour triangles into quadrangles.
@@ -826,75 +1429,73 @@ class LinkID_Gen {
 //           fusion is still performed.
 //=======================================================================
 
-bool SMESH_MeshEditor::TriToQuad (set<const SMDS_MeshElement*> &       theElems,
+bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
                                   SMESH::Controls::NumericalFunctorPtr theCrit,
                                   const double                         theMaxAngle)
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   MESSAGE( "::TriToQuad()" );
 
   if ( !theCrit.get() )
     return false;
 
   SMESHDS_Mesh * aMesh = GetMeshDS();
-  LinkID_Gen aLinkID_Gen( aMesh );
-
 
   // Prepare data for algo: build
   // 1. map of elements with their linkIDs
   // 2. map of linkIDs with their elements
 
-  map< long, list< const SMDS_MeshElement* > > mapLi_listEl;
-  map< long, list< const SMDS_MeshElement* > >::iterator itLE;
-  map< const SMDS_MeshElement*, set< long > >  mapEl_setLi;
-  map< const SMDS_MeshElement*, set< long > >::iterator itEL;
+  map< TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
+  map< TLink, list< const SMDS_MeshElement* > >::iterator itLE;
+  map< const SMDS_MeshElement*, set< TLink > >  mapEl_setLi;
+  map< const SMDS_MeshElement*, set< TLink > >::iterator itEL;
 
-  set<const SMDS_MeshElement*>::iterator itElem;
-  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
-  {
-    const SMDS_MeshElement* elem = (*itElem);
-    if ( !elem || elem->NbNodes() != 3 )
-      continue;
+  TIDSortedElemSet::iterator itElem;
+  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+    const SMDS_MeshElement* elem = *itElem;
+    if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
+    bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
+    if(!IsTria) continue;
 
     // retrieve element nodes
     const SMDS_MeshNode* aNodes [4];
     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
     int i = 0;
-    while ( itN->more() )
-      aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
-    ASSERT( i == 3 );
+    while ( i<3 )
+      aNodes[ i++ ] = cast2Node( itN->next() );
     aNodes[ 3 ] = aNodes[ 0 ];
 
     // fill maps
-    for ( i = 0; i < 3; i++ )
-    {
-      long linkID = aLinkID_Gen.GetLinkID( aNodes[ i ], aNodes[ i+1 ] );
+    for ( i = 0; i < 3; i++ ) {
+      TLink link( aNodes[i], aNodes[i+1] );
       // check if elements sharing a link can be fused
-      itLE = mapLi_listEl.find( linkID );
-      if ( itLE != mapLi_listEl.end() )
-      {
+      itLE = mapLi_listEl.find( link );
+      if ( itLE != mapLi_listEl.end() ) {
         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
           continue;
         const SMDS_MeshElement* elem2 = (*itLE).second.front();
-//         if ( FindShape( elem ) != FindShape( elem2 ))
-//           continue; // do not fuse triangles laying on different shapes
+        //if ( FindShape( elem ) != FindShape( elem2 ))
+        //  continue; // do not fuse triangles laying on different shapes
         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
           continue; // avoid making badly shaped quads
         (*itLE).second.push_back( elem );
       }
-      else
-        mapLi_listEl[ linkID ].push_back( elem );
-      mapEl_setLi [ elem ].insert( linkID );
+      else {
+        mapLi_listEl[ link ].push_back( elem );
+      }
+      mapEl_setLi [ elem ].insert( link );
     }
   }
   // Clean the maps from the links shared by a sole element, ie
   // links to which only one element is bound in mapLi_listEl
 
-  for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ )
-  {
+  for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
     int nbElems = (*itLE).second.size();
     if ( nbElems < 2  ) {
       const SMDS_MeshElement* elem = (*itLE).second.front();
-      long link = (*itLE).first;
+      TLink link = (*itLE).first;
       mapEl_setLi[ elem ].erase( link );
       if ( mapEl_setLi[ elem ].empty() )
         mapEl_setLi.erase( elem );
@@ -903,18 +1504,14 @@ bool SMESH_MeshEditor::TriToQuad (set<const SMDS_MeshElement*> &       theElems,
 
   // Algo: fuse triangles into quadrangles
 
-  while ( ! mapEl_setLi.empty() )
-  {
+  while ( ! mapEl_setLi.empty() ) {
     // Look for the start element:
     // the element having the least nb of shared links
-
     const SMDS_MeshElement* startElem = 0;
     int minNbLinks = 4;
-    for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ )
-    {
+    for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
       int nbLinks = (*itEL).second.size();
-      if ( nbLinks < minNbLinks )
-      {
+      if ( nbLinks < minNbLinks ) {
         startElem = (*itEL).first;
         minNbLinks = nbLinks;
         if ( minNbLinks == 1 )
@@ -924,17 +1521,14 @@ bool SMESH_MeshEditor::TriToQuad (set<const SMDS_MeshElement*> &       theElems,
 
     // search elements to fuse starting from startElem or links of elements
     // fused earlyer - startLinks
-    list< long > startLinks;
-    while ( startElem || !startLinks.empty() )
-    {
-      while ( !startElem && !startLinks.empty() )
-      {
+    list< TLink > startLinks;
+    while ( startElem || !startLinks.empty() ) {
+      while ( !startElem && !startLinks.empty() ) {
         // Get an element to start, by a link
-        long linkId = startLinks.front();
+        TLink linkId = startLinks.front();
         startLinks.pop_front();
         itLE = mapLi_listEl.find( linkId );
-        if ( itLE != mapLi_listEl.end() )
-        {
+        if ( itLE != mapLi_listEl.end() ) {
           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
           for ( ; itE != listElem.end() ; itE++ )
@@ -944,69 +1538,66 @@ bool SMESH_MeshEditor::TriToQuad (set<const SMDS_MeshElement*> &       theElems,
         }
       }
 
-      if ( startElem )
-      {
+      if ( startElem ) {
         // Get candidates to be fused
-
         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
-        long link12, link13;
+        const TLink *link12, *link13;
         startElem = 0;
         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
-        set< long >& setLi = mapEl_setLi[ tr1 ];
+        set< TLink >& setLi = mapEl_setLi[ tr1 ];
         ASSERT( !setLi.empty() );
-        set< long >::iterator itLi;
+        set< TLink >::iterator itLi;
         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
         {
-          long linkID = (*itLi);
-          itLE = mapLi_listEl.find( linkID );
+          const TLink & link = (*itLi);
+          itLE = mapLi_listEl.find( link );
           if ( itLE == mapLi_listEl.end() )
             continue;
+
           const SMDS_MeshElement* elem = (*itLE).second.front();
           if ( elem == tr1 )
             elem = (*itLE).second.back();
           mapLi_listEl.erase( itLE );
           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
             continue;
-          if ( tr2 )
-          {
+          if ( tr2 ) {
             tr3 = elem;
-            link13 = linkID;
+            link13 = &link;
           }
-          else
-          {
+          else {
             tr2 = elem;
-            link12 = linkID;
+            link12 = &link;
           }
 
           // add other links of elem to list of links to re-start from
-          set< long >& links = mapEl_setLi[ elem ];
-          set< long >::iterator it;
-          for ( it = links.begin(); it != links.end(); it++ )
-          {
-            long linkID2 = (*it);
-            if ( linkID2 != linkID )
-              startLinks.push_back( linkID2 );
+          set< TLink >& links = mapEl_setLi[ elem ];
+          set< TLink >::iterator it;
+          for ( it = links.begin(); it != links.end(); it++ ) {
+            const TLink& link2 = (*it);
+            if ( link2 != link )
+              startLinks.push_back( link2 );
           }
         }
 
         // Get nodes of possible quadrangles
-
         const SMDS_MeshNode *n12 [4], *n13 [4];
         bool Ok12 = false, Ok13 = false;
         const SMDS_MeshNode *linkNode1, *linkNode2;
-        if ( tr2 &&
-             aLinkID_Gen.GetNodes( link12, linkNode1, linkNode2 ) &&
-             getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
-          Ok12 = true;
-        if ( tr3 &&
-             aLinkID_Gen.GetNodes( link13, linkNode1, linkNode2 ) &&
-             getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
-          Ok13 = true;
+        if(tr2) {
+          linkNode1 = link12->first;
+          linkNode2 = link12->second;
+          if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
+            Ok12 = true;
+        }
+        if(tr3) {
+          linkNode1 = link13->first;
+          linkNode2 = link13->second;
+          if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
+            Ok13 = true;
+        }
 
         // Choose a pair to fuse
-
-        if ( Ok12 && Ok13 )
-        {
+        if ( Ok12 && Ok13 ) {
           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
           double aBadRate12 = getBadRate( &quad12, theCrit );
@@ -1017,24 +1608,98 @@ bool SMESH_MeshEditor::TriToQuad (set<const SMDS_MeshElement*> &       theElems,
             Ok13 = false;
         }
 
-
         // Make quadrangles
         // and remove fused elems and removed links from the maps
-
         mapEl_setLi.erase( tr1 );
-        if ( Ok12 )
-        {
+        if ( Ok12 ) {
           mapEl_setLi.erase( tr2 );
-          mapLi_listEl.erase( link12 );
-          aMesh->ChangeElementNodes( tr1, n12, 4 );
-          aMesh->RemoveElement( 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);
+            }
+          }
+          else {
+            const SMDS_MeshNode* N1 [6];
+            const SMDS_MeshNode* N2 [6];
+            GetNodesFromTwoTria(tr1,tr2,N1,N2);
+            // now we receive following N1 and N2 (using numeration as above image)
+            // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
+            // i.e. first nodes from both arrays determ new diagonal
+            const SMDS_MeshNode* aNodes[8];
+            aNodes[0] = N1[0];
+            aNodes[1] = N1[1];
+            aNodes[2] = N2[0];
+            aNodes[3] = N2[1];
+            aNodes[4] = N1[3];
+            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 );
+            }
+            // remove middle node (9)
+            GetMeshDS()->RemoveNode( N1[4] );
+          }
         }
-        else if ( Ok13 )
-        {
+        else if ( Ok13 ) {
           mapEl_setLi.erase( tr3 );
-          mapLi_listEl.erase( link13 );
-          aMesh->ChangeElementNodes( tr1, n13, 4 );
-          aMesh->RemoveElement( 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 );
+            }
+          }
+          else {
+            const SMDS_MeshNode* N1 [6];
+            const SMDS_MeshNode* N2 [6];
+            GetNodesFromTwoTria(tr1,tr3,N1,N2);
+            // now we receive following N1 and N2 (using numeration as above image)
+            // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
+            // i.e. first nodes from both arrays determ new diagonal
+            const SMDS_MeshNode* aNodes[8];
+            aNodes[0] = N1[0];
+            aNodes[1] = N1[1];
+            aNodes[2] = N2[0];
+            aNodes[3] = N2[1];
+            aNodes[4] = N1[3];
+            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 );
+            }
+            // remove middle node (9)
+            GetMeshDS()->RemoveNode( N1[4] );
+          }
         }
 
         // Next element to fuse: the rejected one
@@ -1328,6 +1993,55 @@ bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
   return true;
 }*/
 
+//================================================================================
+/*!
+ * \brief Return nodes linked to the given one
+  * \param theNode - the node
+  * \param linkedNodes - the found nodes
+  * \param type - the type of elements to check
+  *
+  * Medium nodes are ignored
+ */
+//================================================================================
+
+void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
+                                       TIDSortedElemSet &   linkedNodes,
+                                       SMDSAbs_ElementType  type )
+{
+  SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
+  while ( elemIt->more() )
+  {
+    const SMDS_MeshElement* elem = elemIt->next();
+    SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
+    if ( elem->GetType() == SMDSAbs_Volume )
+    {
+      SMDS_VolumeTool vol( elem );
+      while ( nodeIt->more() ) {
+        const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
+        if ( theNode != n && vol.IsLinked( theNode, n ))
+          linkedNodes.insert( n );
+      }
+    }
+    else
+    {
+      for ( int i = 0; nodeIt->more(); ++i ) {
+        const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
+        if ( n == theNode ) {
+          int iBefore = i - 1;
+          int iAfter  = i + 1;
+          if ( elem->IsQuadratic() ) {
+            int nb = elem->NbNodes() / 2;
+            iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
+            iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
+          }
+          linkedNodes.insert( elem->GetNode( iAfter ));
+          linkedNodes.insert( elem->GetNode( iBefore ));
+        }
+      }
+    }
+  }
+}
+
 //=======================================================================
 //function : laplacianSmooth
 //purpose  : pulls theNode toward the center of surrounding nodes directly
@@ -1340,38 +2054,15 @@ void laplacianSmooth(const SMDS_MeshNode*                 theNode,
 {
   // find surrounding nodes
 
-  set< const SMDS_MeshNode* > nodeSet;
-  SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
-  while ( elemIt->more() )
-  {
-    const SMDS_MeshElement* elem = elemIt->next();
-    if ( elem->GetType() != SMDSAbs_Face )
-      continue;
-
-    // put all nodes in array
-    int nbNodes = 0, iNode = 0;
-    vector< const SMDS_MeshNode*> aNodes( elem->NbNodes() );
-    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-    while ( itN->more() )
-    {
-      aNodes[ nbNodes ] = static_cast<const SMDS_MeshNode*>( itN->next() );
-      if ( aNodes[ nbNodes ] == theNode )
-        iNode = nbNodes; // index of theNode within aNodes
-      nbNodes++;
-    }
-    // add linked nodes
-    int iAfter = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
-    nodeSet.insert( aNodes[ iAfter ]);
-    int iBefore = ( iNode == 0 ) ? nbNodes - 1 : iNode - 1;
-    nodeSet.insert( aNodes[ iBefore ]);
-  }
+  TIDSortedElemSet nodeSet;
+  SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
 
   // compute new coodrs
 
   double coord[] = { 0., 0., 0. };
-  set< const SMDS_MeshNode* >::iterator nodeSetIt = nodeSet.begin();
+  TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
-    const SMDS_MeshNode* node = (*nodeSetIt);
+    const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
     if ( theSurface.IsNull() ) { // smooth in 3D
       coord[0] += node->X();
       coord[1] += node->Y();
@@ -1423,20 +2114,22 @@ void centroidalSmooth(const SMDS_MeshNode*                 theNode,
 
   // compute new XYZ
 
-  SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
+  SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
   while ( elemIt->more() )
   {
     const SMDS_MeshElement* elem = elemIt->next();
-    if ( elem->GetType() != SMDSAbs_Face )
-      continue;
     nbElems++;
 
     gp_XYZ elemCenter(0.,0.,0.);
     SMESH::Controls::TSequenceOfXYZ aNodePoints;
     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-    while ( itN->more() )
-    {
+    int nn = elem->NbNodes();
+    if(elem->IsQuadratic()) nn = nn/2;
+    int i=0;
+    //while ( itN->more() ) {
+    while ( i<nn ) {
       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
+      i++;
       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
       aNodePoints.push_back( aP );
       if ( !theSurface.IsNull() ) { // smooth in 2D
@@ -1448,12 +2141,11 @@ void centroidalSmooth(const SMDS_MeshNode*                 theNode,
     }
     double elemArea = anAreaFunc.GetValue( aNodePoints );
     totalArea += elemArea;
-    elemCenter /= elem->NbNodes();
+    elemCenter /= nn;
     aNewXYZ += elemCenter * elemArea;
   }
   aNewXYZ /= totalArea;
   if ( !theSurface.IsNull() ) {
-    ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
   }
@@ -1496,18 +2188,23 @@ static bool getClosestUV (Extrema_GenExtPS& projector,
 //           on edges and boundary nodes are always fixed.
 //=======================================================================
 
-void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
-                               set<const SMDS_MeshNode*> &    theFixedNodes,
-                               const SmoothMethod             theSmoothMethod,
-                               const int                      theNbIterations,
-                               double                         theTgtAspectRatio,
-                               const bool                     the2D)
+void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
+                               set<const SMDS_MeshNode*> & theFixedNodes,
+                               const SmoothMethod          theSmoothMethod,
+                               const int                   theNbIterations,
+                               double                      theTgtAspectRatio,
+                               const bool                  the2D)
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
 
   if ( theTgtAspectRatio < 1.0 )
     theTgtAspectRatio = 1.0;
 
+  const double disttol = 1.e-16;
+
   SMESH::Controls::AspectRatio aQualityFunc;
 
   SMESHDS_Mesh* aMesh = GetMeshDS();
@@ -1515,12 +2212,14 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
   if ( theElems.empty() ) {
     // add all faces to theElems
     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
-    while ( fIt->more() )
-      theElems.insert( fIt->next() );
+    while ( fIt->more() ) {
+      const SMDS_MeshElement* face = fIt->next();
+      theElems.insert( face );
+    }
   }
   // get all face ids theElems are on
   set< int > faceIdSet;
-  set< const SMDS_MeshElement* >::iterator itElem;
+  TIDSortedElemSet::iterator itElem;
   if ( the2D )
     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
       int fId = FindShape( *itElem );
@@ -1540,8 +2239,7 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
   // ===============================================
 
   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
-  for ( ; fId != faceIdSet.rend(); ++fId )
-  {
+  for ( ; fId != faceIdSet.rend(); ++fId ) {
     // get face surface and submesh
     Handle(Geom_Surface) surface;
     SMESHDS_SubMesh* faceSubMesh = 0;
@@ -1568,6 +2266,7 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
     // compute UV for them
     // ---------------------------------------------------------
     bool checkBoundaryNodes = false;
+    bool isQuadratic = false;
     set<const SMDS_MeshNode*> setMovableNodes;
     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
@@ -1582,12 +2281,11 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
     int nbElemOnFace = 0;
     itElem = theElems.begin();
      // loop on not yet smoothed elements: look for elems on a face
-    while ( itElem != theElems.end() )
-    {
+    while ( itElem != theElems.end() ) {
       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
         break; // all elements found
 
-      const SMDS_MeshElement* elem = (*itElem);
+      const SMDS_MeshElement* elem = *itElem;
       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
           ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
         ++itElem;
@@ -1597,11 +2295,17 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
       theElems.erase( itElem++ );
       nbElemOnFace++;
 
+      if ( !isQuadratic )
+        isQuadratic = elem->IsQuadratic();
+
       // get movable nodes of elem
       const SMDS_MeshNode* node;
       SMDS_TypeOfPosition posType;
       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-      while ( itN->more() ) {
+      int nn = 0, nbn =  elem->NbNodes();
+      if(elem->IsQuadratic())
+        nbn = nbn/2;
+      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;
@@ -1611,13 +2315,12 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
         {
           // check if all faces around the node are on faceSubMesh
           // because a node on edge may be bound to face
-          SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
+          SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
           bool all = true;
           if ( faceSubMesh ) {
             while ( eIt->more() && all ) {
               const SMDS_MeshElement* e = eIt->next();
-              if ( e->GetType() == SMDSAbs_Face )
-                all = faceSubMesh->Contains( e );
+              all = faceSubMesh->Contains( e );
             }
           }
           if ( all )
@@ -1635,15 +2338,18 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
       // get nodes to check UV
       list< const SMDS_MeshNode* > uvCheckNodes;
       itN = elem->nodesIterator();
-      while ( itN->more() ) {
+      nn = 0; nbn =  elem->NbNodes();
+      if(elem->IsQuadratic())
+        nbn = nbn/2;
+      while ( nn++ < nbn ) {
         node = static_cast<const SMDS_MeshNode*>( itN->next() );
         if ( uvMap.find( node ) == uvMap.end() )
           uvCheckNodes.push_back( node );
         // add nodes of elems sharing node
-//         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
+//         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
 //         while ( eIt->more() ) {
 //           const SMDS_MeshElement* e = eIt->next();
-//           if ( e != elem && e->GetType() == SMDSAbs_Face ) {
+//           if ( e != elem ) {
 //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
 //             while ( nIt->more() ) {
 //               const SMDS_MeshNode* n =
@@ -1656,8 +2362,7 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
       }
       // check UV on face
       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
-      for ( ; n != uvCheckNodes.end(); ++n )
-      {
+      for ( ; n != uvCheckNodes.end(); ++n ) {
         node = *n;
         gp_XY uv( 0, 0 );
         const SMDS_PositionPtr& pos = node->GetPosition();
@@ -1724,29 +2429,25 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
 
     // fix nodes on mesh boundary
 
-    if ( checkBoundaryNodes )
-    {
+    if ( checkBoundaryNodes ) {
       typedef pair<const SMDS_MeshNode*, const SMDS_MeshNode*> TLink;
       map< TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
       map< TLink, int >::iterator link_nb;
       // put all elements links to linkNbMap
       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
-      for ( ; elemIt != elemsOnFace.end(); ++elemIt )
-      {
-        // put elem nodes in array
-        vector< const SMDS_MeshNode* > nodes;
-        nodes.reserve( (*elemIt)->NbNodes() + 1 );
-        SMDS_ElemIteratorPtr itN = (*elemIt)->nodesIterator();
-        while ( itN->more() )
-          nodes.push_back( static_cast<const SMDS_MeshNode*>( itN->next() ));
-        nodes.push_back( nodes.front() );
+      for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
+        const SMDS_MeshElement* elem = (*elemIt);
+        int nbn =  elem->NbNodes();
+        if(elem->IsQuadratic())
+          nbn = nbn/2;
         // loop on elem links: insert them in linkNbMap
-        for ( int iN = 1; iN < nodes.size(); ++iN ) {
+        const SMDS_MeshNode* curNode, *prevNode = elem->GetNode( nbn );
+        for ( int iN = 0; iN < nbn; ++iN ) {
+          curNode = elem->GetNode( iN );
           TLink link;
-          if ( nodes[ iN-1 ]->GetID() < nodes[ iN ]->GetID() )
-            link = make_pair( nodes[ iN-1 ], nodes[ iN ] );
-          else
-            link = make_pair( nodes[ iN ], nodes[ iN-1 ] );
+          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 ));
@@ -1770,11 +2471,9 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
     // -----------------------------------------------------
 
     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
-    if ( !surface.IsNull() )
-    {
+    if ( !surface.IsNull() ) {
       TopExp_Explorer eExp( face, TopAbs_EDGE );
-      for ( ; eExp.More(); eExp.Next() )
-      {
+      for ( ; eExp.More(); eExp.Next() ) {
         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
         if ( !BRep_Tool::IsClosed( edge, face ))
           continue;
@@ -1798,8 +2497,11 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
         // get nodes on seam and its vertices
         list< const SMDS_MeshNode* > seamNodes;
         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
-        while ( nSeamIt->more() )
-          seamNodes.push_back( nSeamIt->next() );
+        while ( nSeamIt->more() ) {
+          const SMDS_MeshNode* node = nSeamIt->next();
+          if ( !isQuadratic || !IsMedium( node ))
+            seamNodes.push_back( node );
+        }
         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
         for ( ; vExp.More(); vExp.Next() ) {
           sm = aMesh->MeshElements( vExp.Current() );
@@ -1811,8 +2513,7 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
         }
         // loop on nodes on seam
         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
-        for ( ; noSeIt != seamNodes.end(); ++noSeIt )
-        {
+        for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
           const SMDS_MeshNode* nSeam = *noSeIt;
           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
           if ( n_uv == uvMap.end() )
@@ -1827,15 +2528,14 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
           uvMap2[ nSeam ] = &listUV.back();
 
           // collect movable nodes linked to ones on seam in nodesNearSeam
-          SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator();
-          while ( eIt->more() )
-          {
+          SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
+          while ( eIt->more() ) {
             const SMDS_MeshElement* e = eIt->next();
-            if ( e->GetType() != SMDSAbs_Face )
-              continue;
             int nbUseMap1 = 0, nbUseMap2 = 0;
             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
-            while ( nIt->more() )
+            int nn = 0, nbn =  e->NbNodes();
+            if(e->IsQuadratic()) nbn = nbn/2;
+            while ( nn++ < nbn )
             {
               const SMDS_MeshNode* n =
                 static_cast<const SMDS_MeshNode*>( nIt->next() );
@@ -1857,10 +2557,10 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
             }
             // for centroidalSmooth all element nodes must
             // be on one side of a seam
-            if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 )
-            {
+            if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
-              while ( nIt->more() ) {
+              nn = 0;
+              while ( nn++ < nbn ) {
                 const SMDS_MeshNode* n =
                   static_cast<const SMDS_MeshNode*>( nIt->next() );
                 setMovableNodes.erase( n );
@@ -1883,12 +2583,10 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
     int it = -1;
     double maxRatio = -1., maxDisplacement = -1.;
     set<const SMDS_MeshNode*>::iterator nodeToMove;
-    for ( it = 0; it < theNbIterations; it++ )
-    {
+    for ( it = 0; it < theNbIterations; it++ ) {
       maxDisplacement = 0.;
       nodeToMove = setMovableNodes.begin();
-      for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ )
-      {
+      for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
         const SMDS_MeshNode* node = (*nodeToMove);
         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
 
@@ -1906,7 +2604,8 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
           maxDisplacement = aDispl;
       }
       // no node movement => exit
-      if ( maxDisplacement < 1.e-16 ) {
+      //if ( maxDisplacement < 1.e-16 ) {
+      if ( maxDisplacement < disttol ) {
         MESSAGE("-- no node movement --");
         break;
       }
@@ -1914,8 +2613,7 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
       // check elements quality
       maxRatio  = 0;
       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
-      for ( ; elemIt != elemsOnFace.end(); ++elemIt )
-      {
+      for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
         const SMDS_MeshElement* elem = (*elemIt);
         if ( !elem || elem->GetType() != SMDSAbs_Face )
           continue;
@@ -1944,10 +2642,8 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
     // new nodes positions are computed,
     // record movement in DS and set new UV
     // ---------------------------------------
-
     nodeToMove = setMovableNodes.begin();
-    for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ )
-    {
+    for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
@@ -1958,7 +2654,50 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
       }
     }
 
+    // move medium nodes of quadratic elements
+    if ( isQuadratic )
+    {
+      SMESH_MesherHelper helper( *GetMesh() );
+      if ( !face.IsNull() )
+        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) {
+          vector<const SMDS_MeshNode*> Ns;
+          Ns.reserve(QF->NbNodes()+1);
+          SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
+          while ( anIter->more() )
+            Ns.push_back( anIter->next() );
+          Ns.push_back( Ns[0] );
+          double x, y, z;
+          for(int i=0; i<QF->NbNodes(); i=i+2) {
+            if ( !surface.IsNull() ) {
+              gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
+              gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
+              gp_XY uv = ( uv1 + uv2 ) / 2.;
+              gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
+              x = xyz.X(); y = xyz.Y(); z = xyz.Z();
+            }
+            else {
+              x = (Ns[i]->X() + Ns[i+2]->X())/2;
+              y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
+              z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
+            }
+            if( fabs( Ns[i+1]->X() - x ) > disttol ||
+                fabs( Ns[i+1]->Y() - y ) > disttol ||
+                fabs( Ns[i+1]->Z() - z ) > disttol ) {
+              // we have to move i+1 node
+              aMesh->MoveNode( Ns[i+1], x, y, z );
+            }
+          }
+        }
+      }
+    }
+
   } // loop on face ids
+
 }
 
 //=======================================================================
@@ -1999,38 +2738,62 @@ static bool isReverse(const SMDS_MeshNode* prevNodes[],
 static void sweepElement(SMESHDS_Mesh*                         aMesh,
                          const SMDS_MeshElement*               elem,
                          const vector<TNodeOfNodeListMapItr> & newNodesItVec,
-                         list<const SMDS_MeshElement*>&        newElems)
+                         list<const SMDS_MeshElement*>&        newElems,
+                         const int nbSteps,
+                         SMESH_SequenceOfElemPtr& myLastCreatedElems)
 {
   // Loop on elem nodes:
   // find new nodes and detect same nodes indices
   int nbNodes = elem->NbNodes();
-  list<const SMDS_MeshNode*>::const_iterator itNN[ nbNodes ];
-  const SMDS_MeshNode* prevNod[ nbNodes ], *nextNod[ nbNodes ];
+  //---PR
+  //list<const SMDS_MeshNode*>::const_iterator itNN[ nbNodes ];
+  vector < list< const SMDS_MeshNode* >::const_iterator > itNN;
+  itNN.reserve(nbNodes);
+  //---PR
+  const SMDS_MeshNode* prevNod[ nbNodes ], *nextNod[ nbNodes ], *midlNod[ nbNodes ];
   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
+  vector<int> sames(nbNodes);
 
-  for ( iNode = 0; iNode < nbNodes; iNode++ )
-  {
+  bool issimple[nbNodes];
+
+  for ( iNode = 0; iNode < nbNodes; iNode++ ) {
     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
     const SMDS_MeshNode*                 node         = nnIt->first;
     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
     if ( listNewNodes.empty() )
       return;
 
+    if(listNewNodes.size()==nbSteps) {
+      issimple[iNode] = true;
+    }
+    else {
+      issimple[iNode] = false;
+    }
+
     itNN[ iNode ] = listNewNodes.begin();
     prevNod[ iNode ] = node;
     nextNod[ iNode ] = listNewNodes.front();
+//cout<<"iNode="<<iNode<<endl;
+//cout<<" prevNod[iNode]="<< prevNod[iNode]<<" nextNod[iNode]="<< nextNod[iNode]<<endl;
     if ( prevNod[ iNode ] != nextNod [ iNode ])
       iNotSameNode = iNode;
     else {
       iSameNode = iNode;
-      nbSame++;
+      //nbSame++;
+      sames[nbSame++] = iNode;
     }
   }
+//cout<<"1 nbSame="<<nbSame<<endl;
   if ( nbSame == nbNodes || nbSame > 2) {
     MESSAGE( " Too many same nodes of element " << elem->GetID() );
     return;
   }
 
+//  if( elem->IsQuadratic() && nbSame>0 ) {
+//    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
+//    return;
+//  }
+
   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
   if ( nbSame > 0 ) {
     iBeforeSame = ( iSameNode == 0 ? nbNodes - 1 : iSameNode - 1 );
@@ -2038,6 +2801,12 @@ static void sweepElement(SMESHDS_Mesh*                         aMesh,
     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
   }
 
+//if(nbNodes==8)
+//cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
+//    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
+//    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
+//    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
+
   // check element orientation
   int i0 = 0, i2 = 2;
   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
@@ -2052,82 +2821,195 @@ static void sweepElement(SMESHDS_Mesh*                         aMesh,
   }
 
   // make new elements
-  int iStep, nbSteps = newNodesItVec[ 0 ]->second.size();
-  for (iStep = 0; iStep < nbSteps; iStep++ )
-  {
+  int iStep;//, nbSteps = newNodesItVec[ 0 ]->second.size();
+  for (iStep = 0; iStep < nbSteps; iStep++ ) {
     // get next nodes
     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
-      nextNod[ iNode ] = *itNN[ iNode ];
-      itNN[ iNode ]++;
+      if(issimple[iNode]) {
+        nextNod[ iNode ] = *itNN[ iNode ];
+        itNN[ iNode ]++;
+      }
+      else {
+        if( elem->GetType()==SMDSAbs_Node ) {
+          // we have to use two nodes
+          midlNod[ iNode ] = *itNN[ iNode ];
+          itNN[ iNode ]++;
+          nextNod[ iNode ] = *itNN[ iNode ];
+          itNN[ iNode ]++;
+        }
+        else if(!elem->IsQuadratic() ||
+           elem->IsQuadratic() && elem->IsMediumNode(prevNod[iNode]) ) {
+          // we have to use each second node
+          itNN[ iNode ]++;
+          nextNod[ iNode ] = *itNN[ iNode ];
+          itNN[ iNode ]++;
+        }
+        else {
+          // we have to use two nodes
+          midlNod[ iNode ] = *itNN[ iNode ];
+          itNN[ iNode ]++;
+          nextNod[ iNode ] = *itNN[ iNode ];
+          itNN[ iNode ]++;
+        }
+      }
     }
     SMDS_MeshElement* aNewElem = 0;
-    switch ( nbNodes )
-    {
-    case 0:
-      return;
-    case 1: { // NODE
-      if ( nbSame == 0 )
-        aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
-      break;
-    }
-    case 2: { // EDGE
-
-      if ( nbSame == 0 )
-        aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
-                                  nextNod[ 1 ], nextNod[ 0 ] );
-      else
-        aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
-                                  nextNod[ iNotSameNode ] );
-      break;
-    }
-    case 3: { // TRIANGLE
-
-      if ( nbSame == 0 )       // --- pentahedron
-        aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
-                                     nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
+    if(!elem->IsPoly()) {
+      switch ( nbNodes ) {
+      case 0:
+        return;
+      case 1: { // NODE
+        if ( nbSame == 0 ) {
+          if(issimple[0])
+            aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
+          else
+            aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
+        }
+        break;
+      }
+      case 2: { // EDGE
+        if ( nbSame == 0 )
+          aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
+                                    nextNod[ 1 ], nextNod[ 0 ] );
+        else
+          aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
+                                    nextNod[ iNotSameNode ] );
+        break;
+      }
 
-      else if ( nbSame == 1 )  // --- pyramid
-        aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
-                                     nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
-                                     nextNod[ iSameNode ]);
+      case 3: { // TRIANGLE or quadratic edge
+        if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
 
-      else // 2 same nodes:      --- tetrahedron
-        aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
-                                     nextNod[ iNotSameNode ]);
-      break;
-    }
-    case 4: { // QUADRANGLE
+          if ( nbSame == 0 )       // --- pentahedron
+            aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
+                                         nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
 
-      if ( nbSame == 0 )       // --- hexahedron
-        aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
-                                     nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
+          else if ( nbSame == 1 )  // --- pyramid
+            aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
+                                         nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
+                                         nextNod[ iSameNode ]);
 
-      else if ( nbSame == 1 )  // --- pyramid + pentahedron
-      {
-        aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
-                                     nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
-                                     nextNod[ iSameNode ]);
-        newElems.push_back( aNewElem );
-        aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
-                                     prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
-                                     nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
-      }
-      else if ( nbSame == 2 )  // pentahedron
-      {
-        if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
-          // iBeforeSame is same too
-          aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
-                                       nextNod[ iOpposSame ], prevNod[ iSameNode ],
-                                       prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
-        else
-          // iAfterSame is same too
-          aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
-                                       nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
-                                       prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
+          else // 2 same nodes:      --- tetrahedron
+            aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
+                                         nextNod[ iNotSameNode ]);
+        }
+        else { // quadratic edge
+          if(nbSame==0) {     // quadratic quadrangle
+            aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
+                                      midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
+          }
+          else if(nbSame==1) { // quadratic triangle
+            if(sames[0]==2)
+              return; // medium node on axis
+            else if(sames[0]==0) {
+              aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
+                                        nextNod[2], midlNod[1], prevNod[2]);
+            }
+            else { // sames[0]==1
+              aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
+                                        midlNod[0], nextNod[2], prevNod[2]);
+            }
+          }
+          else
+            return;
+        }
+        break;
+      }
+      case 4: { // QUADRANGLE
+
+        if ( nbSame == 0 )       // --- hexahedron
+          aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
+                                       nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
+
+        else if ( nbSame == 1 ) { // --- pyramid + pentahedron
+          aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
+                                       nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
+                                       nextNod[ iSameNode ]);
+          newElems.push_back( aNewElem );
+          aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
+                                       prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
+                                       nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
+        }
+        else if ( nbSame == 2 ) { // pentahedron
+          if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
+            // iBeforeSame is same too
+            aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
+                                         nextNod[ iOpposSame ], prevNod[ iSameNode ],
+                                         prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
+          else
+            // iAfterSame is same too
+            aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
+                                         nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
+                                         prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
+        }
+        break;
+      }
+      case 6: { // quadratic triangle
+        // create pentahedron with 15 nodes
+        if(i0>0) { // reversed case
+          aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
+                                       nextNod[0], nextNod[2], nextNod[1],
+                                       prevNod[5], prevNod[4], prevNod[3],
+                                       nextNod[5], nextNod[4], nextNod[3],
+                                       midlNod[0], midlNod[2], midlNod[1]);
+        }
+        else { // not reversed case
+          aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
+                                       nextNod[0], nextNod[1], nextNod[2],
+                                       prevNod[3], prevNod[4], prevNod[5],
+                                       nextNod[3], nextNod[4], nextNod[5],
+                                       midlNod[0], midlNod[1], midlNod[2]);
+        }
+        break;
+      }
+      case 8: { // quadratic quadrangle
+        // create hexahedron with 20 nodes
+        if(i0>0) { // reversed case
+          aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
+                                       nextNod[0], nextNod[3], nextNod[2], nextNod[1],
+                                       prevNod[7], prevNod[6], prevNod[5], prevNod[4],
+                                       nextNod[7], nextNod[6], nextNod[5], nextNod[4],
+                                       midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
+        }
+        else { // not reversed case
+          aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
+                                       nextNod[0], nextNod[1], nextNod[2], nextNod[3],
+                                       prevNod[4], prevNod[5], prevNod[6], prevNod[7],
+                                       nextNod[4], nextNod[5], nextNod[6], nextNod[7],
+                                       midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
+        }
+        break;
+      }
+      default: {
+        // realized for extrusion only
+        //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
+        //vector<int> quantities (nbNodes + 2);
+
+        //quantities[0] = nbNodes; // bottom of prism
+        //for (int inode = 0; inode < nbNodes; inode++) {
+        //  polyedre_nodes[inode] = prevNod[inode];
+        //}
+
+        //quantities[1] = nbNodes; // top of prism
+        //for (int inode = 0; inode < nbNodes; inode++) {
+        //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
+        //}
+
+        //for (int iface = 0; iface < nbNodes; iface++) {
+        //  quantities[iface + 2] = 4;
+        //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
+        //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
+        //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
+        //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
+        //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
+        //}
+        //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
+        break;
+      }
       }
-      break;
     }
-    default: {
+
+    if(!aNewElem) {
       // realized for extrusion only
       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
       vector<int> quantities (nbNodes + 2);
@@ -2152,9 +3034,11 @@ static void sweepElement(SMESHDS_Mesh*                         aMesh,
       }
       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
     }
-    }
-    if ( aNewElem )
+
+    if ( aNewElem ) {
       newElems.push_back( aNewElem );
+      myLastCreatedElems.Append(aNewElem);
+    }
 
     // set new prev nodes
     for ( iNode = 0; iNode < nbNodes; iNode++ )
@@ -2168,30 +3052,44 @@ static void sweepElement(SMESHDS_Mesh*                         aMesh,
 //purpose  : create 1D and 2D elements around swept elements
 //=======================================================================
 
-static void makeWalls (SMESHDS_Mesh*                 aMesh,
-                       TNodeOfNodeListMap &          mapNewNodes,
-                       TElemOfElemListMap &          newElemsMap,
-                       TElemOfVecOfNnlmiMap &        elemNewNodesMap,
-                       set<const SMDS_MeshElement*>& elemSet)
+static void makeWalls (SMESHDS_Mesh*            aMesh,
+                       TNodeOfNodeListMap &     mapNewNodes,
+                       TElemOfElemListMap &     newElemsMap,
+                       TElemOfVecOfNnlmiMap &   elemNewNodesMap,
+                       TIDSortedElemSet&        elemSet,
+                       const int                nbSteps,
+                       SMESH_SequenceOfElemPtr& myLastCreatedElems)
 {
   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
 
   // Find nodes belonging to only one initial element - sweep them to get edges.
 
   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
-  for ( ; nList != mapNewNodes.end(); nList++ )
-  {
+  for ( ; nList != mapNewNodes.end(); nList++ ) {
     const SMDS_MeshNode* node =
       static_cast<const SMDS_MeshNode*>( nList->first );
     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
     int nbInitElems = 0;
-    while ( eIt->more() && nbInitElems < 2 )
-      if ( elemSet.find( eIt->next() ) != elemSet.end() )
+    const SMDS_MeshElement* el = 0;
+    SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
+    while ( eIt->more() && nbInitElems < 2 ) {
+      el = eIt->next();
+      SMDSAbs_ElementType type = el->GetType();
+      if ( type == SMDSAbs_Volume || type < highType ) continue;
+      if ( type > highType ) {
+        nbInitElems = 0;
+        highType = type;
+      }
+      if ( elemSet.find(el) != elemSet.end() )
         nbInitElems++;
+    }
     if ( nbInitElems < 2 ) {
-      vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
-      list<const SMDS_MeshElement*> newEdges;
-      sweepElement( aMesh, node, newNodesItVec, newEdges );
+      bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
+      if(!NotCreateEdge) {
+        vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
+        list<const SMDS_MeshElement*> newEdges;
+        sweepElement( aMesh, node, newNodesItVec, newEdges, nbSteps, myLastCreatedElems );
+      }
     }
   }
 
@@ -2200,62 +3098,103 @@ static void makeWalls (SMESHDS_Mesh*                 aMesh,
 
   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
-  for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
-  {
+  for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
     const SMDS_MeshElement* elem = itElem->first;
     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
 
-    if ( elem->GetType() == SMDSAbs_Edge )
-    {
+    if ( elem->GetType() == SMDSAbs_Edge ) {
       // create a ceiling edge
-      aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
-                     vecNewNodes[ 1 ]->second.back() );
+      if (!elem->IsQuadratic()) {
+        if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
+                               vecNewNodes[ 1 ]->second.back()))
+          myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
+                                                   vecNewNodes[ 1 ]->second.back()));
+      }
+      else {
+        if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
+                               vecNewNodes[ 1 ]->second.back(),
+                               vecNewNodes[ 2 ]->second.back()))
+          myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
+                                                   vecNewNodes[ 1 ]->second.back(),
+                                                   vecNewNodes[ 2 ]->second.back()));
+      }
     }
     if ( elem->GetType() != SMDSAbs_Face )
       continue;
 
+    if(itElem->second.size()==0) continue;
+
     bool hasFreeLinks = false;
 
-    set<const SMDS_MeshElement*> avoidSet;
+    TIDSortedElemSet avoidSet;
     avoidSet.insert( elem );
 
-    // loop on a face nodes
     set<const SMDS_MeshNode*> aFaceLastNodes;
     int iNode, nbNodes = vecNewNodes.size();
-    for ( iNode = 0; iNode < nbNodes; iNode++ )
-    {
-      aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
-      // look for free links of a face
-      int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
-      const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
-      const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
-      // check if a link is free
-      if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ))
-      {
-        hasFreeLinks = true;
-        // make an edge and a ceiling for a new edge
-        if ( !aMesh->FindEdge( n1, n2 ))
-          aMesh->AddEdge( n1, n2 );
-        n1 = vecNewNodes[ iNode ]->second.back();
-        n2 = vecNewNodes[ iNext ]->second.back();
-        if ( !aMesh->FindEdge( n1, n2 ))
-          aMesh->AddEdge( n1, n2 );
+    if(!elem->IsQuadratic()) {
+      // loop on the face nodes
+      for ( iNode = 0; iNode < nbNodes; iNode++ ) {
+        aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
+        // look for free links of the face
+        int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
+        const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
+        const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
+        // check if a link is free
+        if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
+          hasFreeLinks = true;
+          // make an edge and a ceiling for a new edge
+          if ( !aMesh->FindEdge( n1, n2 )) {
+            myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 ));
+          }
+          n1 = vecNewNodes[ iNode ]->second.back();
+          n2 = vecNewNodes[ iNext ]->second.back();
+          if ( !aMesh->FindEdge( n1, n2 )) {
+            myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 ));
+          }
+        }
+      }
+    }
+    else { // elem is quadratic face
+      int nbn = nbNodes/2;
+      for ( iNode = 0; iNode < nbn; iNode++ ) {
+        aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
+        int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
+        const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
+        const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
+        // check if a link is free
+        if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
+          hasFreeLinks = true;
+          // make an edge and a ceiling for a new edge
+          // find medium node
+          const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
+          if ( !aMesh->FindEdge( n1, n2, n3 )) {
+            myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 ));
+          }
+          n1 = vecNewNodes[ iNode ]->second.back();
+          n2 = vecNewNodes[ iNext ]->second.back();
+          n3 = vecNewNodes[ iNode+nbn ]->second.back();
+          if ( !aMesh->FindEdge( n1, n2, n3 )) {
+            myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 ));
+          }
+        }
+      }
+      for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
+        aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
       }
     }
+
     // sweep free links into faces
 
-    if ( hasFreeLinks )
-    {
+    if ( hasFreeLinks )  {
       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
-      int iStep, nbSteps = vecNewNodes[0]->second.size();
+      int iStep; //, nbSteps = vecNewNodes[0]->second.size();
       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
 
       set<const SMDS_MeshNode*> initNodeSet, faceNodeSet;
       for ( iNode = 0; iNode < nbNodes; iNode++ )
         initNodeSet.insert( vecNewNodes[ iNode ]->first );
 
-      for ( volNb = 0; volNb < nbVolumesByStep; volNb++ )
-      {
+      for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
         iVol = 0;
         while ( iVol++ < volNb ) v++;
@@ -2263,37 +3202,69 @@ static void makeWalls (SMESHDS_Mesh*                 aMesh,
         list< int > fInd;
         SMDS_VolumeTool vTool( *v );
         int iF, nbF = vTool.NbFaces();
-        for ( iF = 0; iF < nbF; iF ++ )
+        for ( iF = 0; iF < nbF; iF ++ ) {
           if (vTool.IsFreeFace( iF ) &&
               vTool.GetFaceNodes( iF, faceNodeSet ) &&
               initNodeSet != faceNodeSet) // except an initial face
             fInd.push_back( iF );
+        }
         if ( fInd.empty() )
           continue;
 
         // create faces for all steps
-        for ( iStep = 0; iStep < nbSteps; iStep++ )
-        {
+        // if such a face has been already created by sweep of edge, assure that its orientation is OK
+        for ( iStep = 0; iStep < nbSteps; iStep++ )  {
           vTool.Set( *v );
           vTool.SetExternalNormal();
           list< int >::iterator ind = fInd.begin();
-          for ( ; ind != fInd.end(); ind++ )
-          {
+          for ( ; ind != fInd.end(); ind++ ) {
             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
-            switch ( vTool.NbFaceNodes( *ind ) ) {
-            case 3:
-              aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ); break;
-            case 4:
-              aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ); break;
+            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->GetNode( 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->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
+                aMesh->ChangeElementNodes( f, nodes, nbn );
+              break;
+            }
             default:
-              {
-                int nbPolygonNodes = vTool.NbFaceNodes( *ind );
-                vector<const SMDS_MeshNode*> polygon_nodes (nbPolygonNodes);
-                for (int inode = 0; inode < nbPolygonNodes; inode++) {
-                  polygon_nodes[inode] = nodes[inode];
+              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->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
+                    aMesh->ChangeElementNodes( f, nodes, nbn );
                 }
-                aMesh->AddPolygonalFace(polygon_nodes);
-                break;
+                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->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
+                    aMesh->ChangeElementNodes( f, nodes, nbn );
+                }
+              }
+              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->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
+                  aMesh->ChangeElementNodes( f, nodes, nbn );
               }
             }
           }
@@ -2307,36 +3278,48 @@ static void makeWalls (SMESHDS_Mesh*                 aMesh,
     // make a ceiling face with a normal external to a volume
 
     SMDS_VolumeTool lastVol( itElem->second.back() );
+
     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
-    if ( iF >= 0 )
-    {
+    if ( iF >= 0 ) {
       lastVol.SetExternalNormal();
       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
-      switch ( lastVol.NbFaceNodes( iF ) ) {
+      int nbn = lastVol.NbFaceNodes( iF );
+      switch ( nbn ) {
       case 3:
         if (!hasFreeLinks ||
             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
-          aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] );
+          myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
         break;
       case 4:
         if (!hasFreeLinks ||
             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
-          aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] );
+          myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
         break;
       default:
-        {
-          int nbPolygonNodes = lastVol.NbFaceNodes( iF );
-          vector<const SMDS_MeshNode*> polygon_nodes (nbPolygonNodes);
-          for (int inode = 0; inode < nbPolygonNodes; inode++) {
-            polygon_nodes[inode] = nodes[inode];
+        if(itElem->second.back()->IsQuadratic()) {
+          if(nbn==6) {
+            if (!hasFreeLinks ||
+                !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
+                                 nodes[1], nodes[3], nodes[5]) ) {
+              myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
+                                                       nodes[1], nodes[3], nodes[5]));
+            }
           }
+          else { // nbn==8
+            if (!hasFreeLinks ||
+                !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
+                                 nodes[1], nodes[3], nodes[5], nodes[7]) )
+              myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
+                                                       nodes[1], nodes[3], nodes[5], nodes[7]));
+          }
+        }
+        else {
+          vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
-            aMesh->AddPolygonalFace(polygon_nodes);
+            myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
         }
-        break;
-      }
+      } // switch
     }
-
   } // loop on swept elements
 }
 
@@ -2345,15 +3328,21 @@ static void makeWalls (SMESHDS_Mesh*                 aMesh,
 //purpose  :
 //=======================================================================
 
-void SMESH_MeshEditor::RotationSweep(set<const SMDS_MeshElement*> & theElems,
-                                     const gp_Ax1&                  theAxis,
-                                     const double                   theAngle,
-                                     const int                      theNbSteps,
-                                     const double                   theTol)
+void SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
+                                     const gp_Ax1&      theAxis,
+                                     const double       theAngle,
+                                     const int          theNbSteps,
+                                     const double       theTol,
+                                     const bool         theMakeWalls)
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   MESSAGE( "RotationSweep()");
   gp_Trsf aTrsf;
   aTrsf.SetRotation( theAxis, theAngle );
+  gp_Trsf aTrsf2;
+  aTrsf2.SetRotation( theAxis, theAngle/2. );
 
   gp_Lin aLine( theAxis );
   double aSqTol = theTol * theTol;
@@ -2365,11 +3354,10 @@ void SMESH_MeshEditor::RotationSweep(set<const SMDS_MeshElement*> & theElems,
   TElemOfElemListMap newElemsMap;
 
   // loop on theElems
-  set< const SMDS_MeshElement* >::iterator itElem;
-  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
-  {
-    const SMDS_MeshElement* elem = (*itElem);
-    if ( !elem )
+  TIDSortedElemSet::iterator itElem;
+  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+    const SMDS_MeshElement* elem = *itElem;
+    if ( !elem || elem->GetType() == SMDSAbs_Volume )
       continue;
     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
     newNodesItVec.reserve( elem->NbNodes() );
@@ -2382,8 +3370,7 @@ void SMESH_MeshEditor::RotationSweep(set<const SMDS_MeshElement*> & theElems,
       const SMDS_MeshNode* node =
         static_cast<const SMDS_MeshNode*>( itN->next() );
       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
-      if ( nIt == mapNewNodes.end() )
-      {
+      if ( nIt == mapNewNodes.end() ) {
         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
 
@@ -2395,80 +3382,164 @@ void SMESH_MeshEditor::RotationSweep(set<const SMDS_MeshElement*> & theElems,
         const SMDS_MeshNode * newNode = node;
         for ( int i = 0; i < theNbSteps; i++ ) {
           if ( !isOnAxis ) {
-            aTrsf.Transforms( coord[0], coord[1], coord[2] );
+            if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+              // create two nodes
+              aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+              //aTrsf.Transforms( coord[0], coord[1], coord[2] );
+              newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+              myLastCreatedNodes.Append(newNode);
+              listNewNodes.push_back( newNode );
+              aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+              //aTrsf.Transforms( coord[0], coord[1], coord[2] );
+            }
+            else {
+              aTrsf.Transforms( coord[0], coord[1], coord[2] );
+            }
             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+            myLastCreatedNodes.Append(newNode);
           }
           listNewNodes.push_back( newNode );
         }
       }
+      else {
+        // if current elem is quadratic and current node is not medium
+        // we have to check - may be it is needed to insert additional nodes
+        if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+          list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
+          if(listNewNodes.size()==theNbSteps) {
+            listNewNodes.clear();
+            // make new nodes
+            gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
+            double coord[3];
+            aXYZ.Coord( coord[0], coord[1], coord[2] );
+            const SMDS_MeshNode * newNode = node;
+            for(int i = 0; i<theNbSteps; i++) {
+              aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+              newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+              myLastCreatedNodes.Append(newNode);
+              listNewNodes.push_back( newNode );
+              aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+              newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+              myLastCreatedNodes.Append(newNode);
+              listNewNodes.push_back( newNode );
+            }
+          }
+        }
+      }
       newNodesItVec.push_back( nIt );
     }
     // make new elements
-    sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem] );
+    sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], theNbSteps, myLastCreatedElems );
   }
 
-  makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElems );
-
+  if ( theMakeWalls )
+    makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes,
+               theElems, theNbSteps, myLastCreatedElems );
 }
 
 
 //=======================================================================
 //function : CreateNode
-//purpose  : 
+//purpose  :
 //=======================================================================
 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
                                                   const double y,
                                                   const double z,
-                                                  const double tolnode)
+                                                  const double tolnode,
+                                                  SMESH_SequenceOfNode& aNodes)
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   gp_Pnt P1(x,y,z);
   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
-  // try to search in sequence of existing nodes
-  SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
-  while(itn->more()) {
-    const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
-    gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
-    if(P1.Distance(P2)<tolnode)
-      return aN;
-  }    
-  // create new node and return it
-  const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
-  return NewNode;
-}
-
+
+  // try to search in sequence of existing nodes
+  // if aNodes.Length()>0 we 'nave to use given sequence
+  // else - use all nodes of mesh
+  if(aNodes.Length()>0) {
+    int i;
+    for(i=1; i<=aNodes.Length(); i++) {
+      gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
+      if(P1.Distance(P2)<tolnode)
+        return aNodes.Value(i);
+    }
+  }
+  else {
+    SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
+    while(itn->more()) {
+      const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
+      gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
+      if(P1.Distance(P2)<tolnode)
+        return aN;
+    }
+  }
+
+  // create new node and return it
+  const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
+  myLastCreatedNodes.Append(NewNode);
+  return NewNode;
+}
+
 
 //=======================================================================
 //function : ExtrusionSweep
 //purpose  :
 //=======================================================================
 
-void SMESH_MeshEditor::ExtrusionSweep
-                    (set<const SMDS_MeshElement*> & theElems,
-                     const gp_Vec&                  theStep,
-                     const int                      theNbSteps,
-                     TElemOfElemListMap&            newElemsMap,
-                     const int                      theFlags,
-                     const double                   theTolerance)
+void SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
+                                       const gp_Vec&       theStep,
+                                       const int           theNbSteps,
+                                       TElemOfElemListMap& newElemsMap,
+                                       const int           theFlags,
+                                       const double        theTolerance)
 {
-  gp_Trsf aTrsf;
-  aTrsf.SetTranslation( theStep );
+  ExtrusParam aParams;
+  aParams.myDir = gp_Dir(theStep);
+  aParams.myNodes.Clear();
+  aParams.mySteps = new TColStd_HSequenceOfReal;
+  int i;
+  for(i=1; i<=theNbSteps; i++)
+    aParams.mySteps->Append(theStep.Magnitude());
+
+  ExtrusionSweep(theElems,aParams,newElemsMap,theFlags,theTolerance);
+
+}
+
+
+//=======================================================================
+//function : ExtrusionSweep
+//purpose  :
+//=======================================================================
+
+void SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
+                                       ExtrusParam&        theParams,
+                                       TElemOfElemListMap& newElemsMap,
+                                       const int           theFlags,
+                                       const double        theTolerance)
+{
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
 
   SMESHDS_Mesh* aMesh = GetMeshDS();
 
+  int nbsteps = theParams.mySteps->Length();
+
   TNodeOfNodeListMap mapNewNodes;
+  //TNodeOfNodeVecMap mapNewNodes;
   TElemOfVecOfNnlmiMap mapElemNewNodes;
-  //TElemOfElemListMap newElemsMap;
+  //TElemOfVecOfMapNodesMap mapElemNewNodes;
 
   // loop on theElems
-  set< const SMDS_MeshElement* >::iterator itElem;
-  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
-  {
+  TIDSortedElemSet::iterator itElem;
+  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
     // check element type
-    const SMDS_MeshElement* elem = (*itElem);
-    if ( !elem )
+    const SMDS_MeshElement* elem = *itElem;
+    if ( !elem  || elem->GetType() == SMDSAbs_Volume )
       continue;
 
     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
+    //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
     newNodesItVec.reserve( elem->NbNodes() );
 
     // loop on elem nodes
@@ -2479,36 +3550,103 @@ void SMESH_MeshEditor::ExtrusionSweep
       const SMDS_MeshNode* node =
         static_cast<const SMDS_MeshNode*>( itN->next() );
       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
-      if ( nIt == mapNewNodes.end() )
-      {
+      //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
+      if ( nIt == mapNewNodes.end() ) {
         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
+        //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
+        //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
+        //vecNewNodes.reserve(nbsteps);
 
         // make new nodes
         double coord[] = { node->X(), node->Y(), node->Z() };
-        for ( int i = 0; i < theNbSteps; i++ ) {
-          aTrsf.Transforms( coord[0], coord[1], coord[2] );
+        //int nbsteps = theParams.mySteps->Length();
+        for ( int i = 0; i < nbsteps; i++ ) {
+          if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+            // create additional node
+            double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
+            double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
+            double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
+            if( theFlags & EXTRUSION_FLAG_SEW ) {
+              const SMDS_MeshNode * newNode = CreateNode(x, y, z,
+                                                         theTolerance, theParams.myNodes);
+              listNewNodes.push_back( newNode );
+            }
+            else {
+              const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
+              myLastCreatedNodes.Append(newNode);
+              listNewNodes.push_back( newNode );
+            }
+          }
+          //aTrsf.Transforms( coord[0], coord[1], coord[2] );
+          coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
+          coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
+          coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
           if( theFlags & EXTRUSION_FLAG_SEW ) {
-            const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1],
-                                                       coord[2], theTolerance);
+            const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
+                                                       theTolerance, theParams.myNodes);
             listNewNodes.push_back( newNode );
+            //vecNewNodes[i]=newNode;
           }
           else {
             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+            myLastCreatedNodes.Append(newNode);
             listNewNodes.push_back( newNode );
+            //vecNewNodes[i]=newNode;
+          }
+        }
+      }
+      else {
+        // if current elem is quadratic and current node is not medium
+        // we have to check - may be it is needed to insert additional nodes
+        if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+          list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
+          if(listNewNodes.size()==nbsteps) {
+            listNewNodes.clear();
+            double coord[] = { node->X(), node->Y(), node->Z() };
+            for ( int i = 0; i < nbsteps; i++ ) {
+              double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
+              double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
+              double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
+              if( theFlags & EXTRUSION_FLAG_SEW ) {
+                const SMDS_MeshNode * newNode = CreateNode(x, y, z,
+                                                           theTolerance, theParams.myNodes);
+                listNewNodes.push_back( newNode );
+              }
+              else {
+                const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
+                myLastCreatedNodes.Append(newNode);
+                listNewNodes.push_back( newNode );
+              }
+              coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
+              coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
+              coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
+              if( theFlags & EXTRUSION_FLAG_SEW ) {
+                const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
+                                                           theTolerance, theParams.myNodes);
+                listNewNodes.push_back( newNode );
+              }
+              else {
+                const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+                myLastCreatedNodes.Append(newNode);
+                listNewNodes.push_back( newNode );
+              }
+            }
           }
         }
       }
       newNodesItVec.push_back( nIt );
     }
     // make new elements
-    sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem] );
+    sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], nbsteps, myLastCreatedElems );
   }
+
   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
-    makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElems );
+    makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, myLastCreatedElems );
   }
 }
 
+
 //=======================================================================
 //class    : SMESH_MeshEditor_PathPoint
 //purpose  : auxiliary class
@@ -2558,20 +3696,23 @@ protected:
 //purpose  :
 //=======================================================================
 SMESH_MeshEditor::Extrusion_Error
-  SMESH_MeshEditor::ExtrusionAlongTrack (std::set<const SMDS_MeshElement*> & theElements,
-                                        SMESH_subMesh* theTrack,
+  SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
+                                        SMESH_subMesh*       theTrack,
                                         const SMDS_MeshNode* theN1,
-                                        const bool theHasAngles,
-                                        std::list<double>& theAngles,
-                                        const bool theHasRefPoint,
-                                        const gp_Pnt& theRefPoint)
+                                        const bool           theHasAngles,
+                                        list<double>&        theAngles,
+                                        const bool           theHasRefPoint,
+                                        const gp_Pnt&        theRefPoint)
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   MESSAGE("SMESH_MeshEditor::ExtrusionAlongTrack")
   int j, aNbTP, aNbE, aNb;
   double aT1, aT2, aT, aAngle, aX, aY, aZ;
   std::list<double> aPrms;
   std::list<double>::iterator aItD;
-  std::set< const SMDS_MeshElement* >::iterator itElem;
+  TIDSortedElemSet::iterator itElem;
 
   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
   gp_Pnt aP3D, aV0;
@@ -2711,7 +3852,7 @@ SMESH_MeshEditor::Extrusion_Error
 
     itElem = theElements.begin();
     for ( ; itElem != theElements.end(); itElem++ ) {
-      const SMDS_MeshElement* elem = (*itElem);
+      const SMDS_MeshElement* elem = *itElem;
 
       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
       while ( itN->more() ) {
@@ -2740,7 +3881,7 @@ SMESH_MeshEditor::Extrusion_Error
 
   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
     // check element type
-    const SMDS_MeshElement* elem = (*itElem);
+    const SMDS_MeshElement* elem = *itElem;
     aTypeE = elem->GetType();
     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
       continue;
@@ -2813,10 +3954,20 @@ SMESH_MeshEditor::Extrusion_Error
          }
 
          // make new node
+          if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+            // create additional node
+            double x = ( aPN1.X() + aPN0.X() )/2.;
+            double y = ( aPN1.Y() + aPN0.Y() )/2.;
+            double z = ( aPN1.Z() + aPN0.Z() )/2.;
+            const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
+            myLastCreatedNodes.Append(newNode);
+            listNewNodes.push_back( newNode );
+          }
          aX = aPN1.X();
          aY = aPN1.Y();
          aZ = aPN1.Z();
          const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
+          myLastCreatedNodes.Append(newNode);
          listNewNodes.push_back( newNode );
 
          aPN0 = aPN1;
@@ -2825,13 +3976,47 @@ SMESH_MeshEditor::Extrusion_Error
          aDT0x = aDT1x;
        }
       }
+
+      else {
+        // if current elem is quadratic and current node is not medium
+        // we have to check - may be it is needed to insert additional nodes
+        if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+          list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
+          if(listNewNodes.size()==aNbTP-1) {
+            vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
+            gp_XYZ P(node->X(), node->Y(), node->Z());
+            list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
+            int i;
+            for(i=0; i<aNbTP-1; i++) {
+              const SMDS_MeshNode* N = *it;
+              double x = ( N->X() + P.X() )/2.;
+              double y = ( N->Y() + P.Y() )/2.;
+              double z = ( N->Z() + P.Z() )/2.;
+              const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
+              myLastCreatedNodes.Append(newN);
+              aNodes[2*i] = newN;
+              aNodes[2*i+1] = N;
+              P = gp_XYZ(N->X(),N->Y(),N->Z());
+            }
+            listNewNodes.clear();
+            for(i=0; i<2*(aNbTP-1); i++) {
+              listNewNodes.push_back(aNodes[i]);
+            }
+          }
+        }
+      }
+
       newNodesItVec.push_back( nIt );
     }
     // make new elements
-    sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem] );
+    //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
+    //              newNodesItVec[0]->second.size(), myLastCreatedElems );
+    sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
+                  aNbTP-1, myLastCreatedElems );
   }
 
-  makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElements );
+  makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElements,
+             aNbTP-1, myLastCreatedElems );
 
   return EXTR_OK;
 }
@@ -2841,10 +4026,13 @@ SMESH_MeshEditor::Extrusion_Error
 //purpose  :
 //=======================================================================
 
-void SMESH_MeshEditor::Transform (set<const SMDS_MeshElement*> & theElems,
-                                  const gp_Trsf&                 theTrsf,
-                                  const bool                     theCopy)
+void SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
+                                  const gp_Trsf&     theTrsf,
+                                  const bool         theCopy)
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   bool needReverse;
   switch ( theTrsf.Form() ) {
   case gp_PntMirror:
@@ -2862,13 +4050,12 @@ void SMESH_MeshEditor::Transform (set<const SMDS_MeshElement*> & theElems,
 
   // elements sharing moved nodes; those of them which have all
   // nodes mirrored but are not in theElems are to be reversed
-  set<const SMDS_MeshElement*> inverseElemSet;
+  TIDSortedElemSet inverseElemSet;
 
   // loop on theElems
-  set< const SMDS_MeshElement* >::iterator itElem;
-  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
-  {
-    const SMDS_MeshElement* elem = (*itElem);
+  TIDSortedElemSet::iterator itElem;
+  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+    const SMDS_MeshElement* elem = *itElem;
     if ( !elem )
       continue;
 
@@ -2888,8 +4075,10 @@ void SMESH_MeshEditor::Transform (set<const SMDS_MeshElement*> & theElems,
       coord[2] = node->Z();
       theTrsf.Transforms( coord[0], coord[1], coord[2] );
       const SMDS_MeshNode * newNode = node;
-      if ( theCopy )
+      if ( theCopy ) {
         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+        myLastCreatedNodes.Append(newNode);
+      }
       else {
         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
         // node position on shape becomes invalid
@@ -2901,8 +4090,10 @@ void SMESH_MeshEditor::Transform (set<const SMDS_MeshElement*> & theElems,
       // keep inverse elements
       if ( !theCopy && needReverse ) {
         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
-        while ( invElemIt->more() )
-          inverseElemSet.insert( invElemIt->next() );
+        while ( invElemIt->more() ) {
+          const SMDS_MeshElement* iel = invElemIt->next();
+          inverseElemSet.insert( iel );
+        }
       }
     }
   }
@@ -2913,7 +4104,7 @@ void SMESH_MeshEditor::Transform (set<const SMDS_MeshElement*> & theElems,
     return;
 
   if ( !inverseElemSet.empty()) {
-    set<const SMDS_MeshElement*>::iterator invElemIt = inverseElemSet.begin();
+    TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
     for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
       theElems.insert( *invElemIt );
   }
@@ -2937,9 +4128,8 @@ void SMESH_MeshEditor::Transform (set<const SMDS_MeshElement*> & theElems,
     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
   };
 
-  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
-  {
-    const SMDS_MeshElement* elem = (*itElem);
+  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+    const SMDS_MeshElement* elem = *itElem;
     if ( !elem || elem->GetType() == SMDSAbs_Node )
       continue;
 
@@ -2972,8 +4162,9 @@ void SMESH_MeshEditor::Transform (set<const SMDS_MeshElement*> & theElems,
             continue; // not all nodes transformed
 
           if ( theCopy ) {
-            aMesh->AddPolygonalFace(poly_nodes);
-          } else {
+            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
+          }
+          else {
             aMesh->ChangePolygonNodes(elem, poly_nodes);
           }
         }
@@ -3010,8 +4201,9 @@ void SMESH_MeshEditor::Transform (set<const SMDS_MeshElement*> & theElems,
             continue; // not all nodes transformed
 
           if ( theCopy ) {
-            aMesh->AddPolyhedralVolume(poly_nodes, quantities);
-          } else {
+            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
+          }
+          else {
             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
           }
         }
@@ -3029,12 +4221,46 @@ void SMESH_MeshEditor::Transform (set<const SMDS_MeshElement*> & theElems,
       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
-    const SMDS_MeshNode* nodes[8];
+    vector<const SMDS_MeshNode*> nodes(nbNodes);
     int iNode = 0;
     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-    while ( itN->more() )
-    {
+    while ( itN->more() ) {
       const SMDS_MeshNode* node =
         static_cast<const SMDS_MeshNode*>( itN->next() );
       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
@@ -3045,40 +4271,15 @@ void SMESH_MeshEditor::Transform (set<const SMDS_MeshElement*> & theElems,
     if ( iNode != nbNodes )
       continue; // not all nodes transformed
 
-    if ( theCopy )
-    {
-      // add a new element
-      switch ( elemType ) {
-      case SMDSAbs_Edge:
-        aMesh->AddEdge( nodes[ 0 ], nodes[ 1 ] );
-        break;
-      case SMDSAbs_Face:
-        if ( nbNodes == 3 )
-          aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] );
-        else
-          aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ]);
-        break;
-      case SMDSAbs_Volume:
-        if ( nbNodes == 4 )
-          aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ] );
-        else if ( nbNodes == 8 )
-          aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ],
-                            nodes[ 4 ], nodes[ 5 ], nodes[ 6 ] , nodes[ 7 ]);
-        else if ( nbNodes == 6 )
-          aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ],
-                            nodes[ 4 ], nodes[ 5 ]);
-        else if ( nbNodes == 5 )
-          aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ],
-                            nodes[ 4 ]);
-        break;
-      default:;
-      }
+    if ( theCopy ) {
+      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() ))
+        myLastCreatedElems.Append( copy );
     }
     else
     {
       // reverse element as it was reversed by transformation
       if ( nbNodes > 2 )
-        aMesh->ChangeElementNodes( elem, nodes, nbNodes );
+        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
     }
   }
 }
@@ -3086,52 +4287,134 @@ void SMESH_MeshEditor::Transform (set<const SMDS_MeshElement*> & theElems,
 //=======================================================================
 //function : FindCoincidentNodes
 //purpose  : Return list of group of nodes close to each other within theTolerance
-//           Search among theNodes or in the whole mesh if theNodes is empty.
+//           Search among theNodes or in the whole mesh if theNodes is empty using
+//           an Octree algorithm
 //=======================================================================
 
 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
                                             const double                theTolerance,
                                             TListOfListOfNodes &        theGroupsOfNodes)
 {
-  double tol2 = theTolerance * theTolerance;
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
 
-  list<const SMDS_MeshNode*> nodes;
+  set<const SMDS_MeshNode*> nodes;
   if ( theNodes.empty() )
   { // get all nodes in the mesh
     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
     while ( nIt->more() )
-      nodes.push_back( nIt->next() );
+      nodes.insert( nodes.end(),nIt->next());
   }
   else
+    nodes=theNodes;
+  SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
+
+}
+
+//=======================================================================
+/*!
+ * \brief Implementation of search for the node closest to point
+ */
+//=======================================================================
+
+struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
+{
+  /*!
+   * \brief Constructor
+   */
+  SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
   {
-    nodes.insert( nodes.end(), theNodes.begin(), theNodes.end() );
+    set<const SMDS_MeshNode*> nodes;
+    if ( theMesh ) {
+      SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
+      while ( nIt->more() )
+        nodes.insert( nodes.end(), nIt->next() );
+    }
+    myOctreeNode = new SMESH_OctreeNode(nodes) ;
   }
-
-  list<const SMDS_MeshNode*>::iterator it2, it1 = nodes.begin();
-  for ( ; it1 != nodes.end(); it1++ )
+  /*!
+   * \brief Do it's job
+   */
+  const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
   {
-    const SMDS_MeshNode* n1 = *it1;
-    gp_Pnt p1( n1->X(), n1->Y(), n1->Z() );
-
-    list<const SMDS_MeshNode*> * groupPtr = 0;
-    it2 = it1;
-    for ( it2++; it2 != nodes.end(); it2++ )
+    SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
+    list<const SMDS_MeshNode*> nodes;
+    const double precision = 1e-6;
+    myOctreeNode->NodesAround( &tgtNode, &nodes, precision );
+
+    double minSqDist = DBL_MAX;
+    Bnd_B3d box;
+    if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
     {
-      const SMDS_MeshNode* n2 = *it2;
-      gp_Pnt p2( n2->X(), n2->Y(), n2->Z() );
-      if ( p1.SquareDistance( p2 ) <= tol2 )
+      // sort leafs by their distance from thePnt
+      typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
+      TDistTreeMap treeMap;
+      list< SMESH_OctreeNode* > treeList;
+      list< SMESH_OctreeNode* >::iterator trIt;
+      treeList.push_back( myOctreeNode );
+      for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
       {
-        if ( !groupPtr ) {
-          theGroupsOfNodes.push_back( list<const SMDS_MeshNode*>() );
-          groupPtr = & theGroupsOfNodes.back();
-          groupPtr->push_back( n1 );
+        SMESH_OctreeNode* tree = *trIt;
+        if ( !tree->isLeaf() ) { // put children to the queue
+          SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
+          while ( cIt->more() )
+            treeList.push_back( cIt->next() );
         }
-        groupPtr->push_back( n2 );
-        it2 = nodes.erase( it2 );
-        it2--;
+        else if ( tree->NbNodes() ) { // put tree to treeMap
+          tree->getBox( box );
+          double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
+          pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
+          if ( !it_in.second ) // not unique distance to box center
+            treeMap.insert( it_in.first, make_pair( sqDist - 1e-13*treeMap.size(), tree ));
+        }
+      }
+      // find distance after which there is no sense to check tree's
+      double sqLimit = DBL_MAX;
+      TDistTreeMap::iterator sqDist_tree = treeMap.begin();
+      if ( treeMap.size() > 5 ) {
+        SMESH_OctreeNode* closestTree = sqDist_tree->second;
+        closestTree->getBox( box );
+        double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
+        sqLimit = limit * limit;
+      }
+      // get all nodes from trees
+      for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
+        if ( sqDist_tree->first > sqLimit )
+          break;
+        SMESH_OctreeNode* tree = sqDist_tree->second;
+        tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
       }
     }
+    // find closest among nodes
+    minSqDist = DBL_MAX;
+    const SMDS_MeshNode* closestNode = 0;
+    list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
+    for ( ; nIt != nodes.end(); ++nIt ) {
+      double sqDist = thePnt.SquareDistance( TNodeXYZ( *nIt ) );
+      if ( minSqDist > sqDist ) {
+        closestNode = *nIt;
+        minSqDist = sqDist;
+      }
+    }
+    return closestNode;
   }
+  /*!
+   * \brief Destructor
+   */
+  ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
+private:
+  SMESH_OctreeNode* myOctreeNode;
+};
+
+//=======================================================================
+/*!
+ * \brief Return SMESH_NodeSearcher
+ */
+//=======================================================================
+
+SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
+{
+  return new SMESH_NodeSearcherImpl( GetMeshDS() );
 }
 
 //=======================================================================
@@ -3224,6 +4507,9 @@ int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNode
 
 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   SMESHDS_Mesh* aMesh = GetMeshDS();
 
   TNodeNodeMap nodeNodeMap; // node to replace - new node
@@ -3233,13 +4519,11 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
   // Fill nodeNodeMap and elems
 
   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
-  for ( ; grIt != theGroupsOfNodes.end(); grIt++ )
-  {
+  for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
     list<const SMDS_MeshNode*>& nodes = *grIt;
     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
     const SMDS_MeshNode* nToKeep = *nIt;
-    for ( ; nIt != nodes.end(); nIt++ )
-    {
+    for ( ++nIt; nIt != nodes.end(); nIt++ ) {
       const SMDS_MeshNode* nToRemove = *nIt;
       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
       if ( nToRemove != nToKeep ) {
@@ -3248,15 +4532,16 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
       }
 
       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
-      while ( invElemIt->more() )
-        elems.insert( invElemIt->next() );
+      while ( invElemIt->more() ) {
+        const SMDS_MeshElement* elem = invElemIt->next();
+          elems.insert(elem);
+      }
     }
   }
   // Change element nodes or remove an element
 
   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
-  for ( ; eIt != elems.end(); eIt++ )
-  {
+  for ( ; eIt != elems.end(); eIt++ ) {
     const SMDS_MeshElement* elem = *eIt;
     int nbNodes = elem->NbNodes();
     int aShapeId = FindShape( elem );
@@ -3267,8 +4552,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 
     // get new seq of nodes
     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-    while ( itN->more() )
-    {
+    while ( itN->more() ) {
       const SMDS_MeshNode* n =
         static_cast<const SMDS_MeshNode*>( itN->next() );
 
@@ -3288,8 +4572,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 
     bool isOk = true;
     int nbUniqueNodes = nodeSet.size();
-    if ( nbNodes != nbUniqueNodes ) // some nodes stick
-    {
+    if ( nbNodes != nbUniqueNodes ) { // some nodes stick
       // Polygons and Polyhedral volumes
       if (elem->IsPoly()) {
 
@@ -3314,19 +4597,23 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
                 poly_nodes[ii] = polygons_nodes[inode];
               }
               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
+              myLastCreatedElems.Append(newElem);
               if (aShapeId)
                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
             }
             aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
-          } else {
+          }
+          else {
             rmElemIds.push_back(elem->GetID());
           }
 
-        } else if (elem->GetType() == SMDSAbs_Volume) {
+        }
+        else if (elem->GetType() == SMDSAbs_Volume) {
           // Polyhedral volume
           if (nbUniqueNodes < 4) {
             rmElemIds.push_back(elem->GetID());
-          } else {
+          }
+          else {
             // each face has to be analized in order to check volume validity
             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
               static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
@@ -3361,11 +4648,13 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
               else
                 rmElemIds.push_back(elem->GetID());
 
-            } else {
+            }
+            else {
               rmElemIds.push_back(elem->GetID());
             }
           }
-        } else {
+        }
+        else {
         }
 
         continue;
@@ -3423,6 +4712,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
                                curNodes[ 4 ],
                                curNodes[ 5 ],
                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
+            myLastCreatedElems.Append(newElem);
             if ( aShapeId )
               aMesh->SetMeshElementOnShape( newElem, aShapeId );
             // 2. : reverse a bottom
@@ -3436,7 +4726,96 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
         else
           isOk = false;
         break;
-      case 8: { //////////////////////////////////// HEXAHEDRON
+      case 8: {
+        if(elem->IsQuadratic()) { // Quadratic quadrangle
+          //   1    5    2
+          //    +---+---+
+          //    |       |
+          //    |       |
+          //   4+       +6
+          //    |       |
+          //    |       |
+          //    +---+---+
+          //   0    7    3
+          isOk = false;
+          if(nbRepl==3) {
+            nbUniqueNodes = 6;
+            if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
+              uniqueNodes[0] = curNodes[0];
+              uniqueNodes[1] = curNodes[2];
+              uniqueNodes[2] = curNodes[3];
+              uniqueNodes[3] = curNodes[5];
+              uniqueNodes[4] = curNodes[6];
+              uniqueNodes[5] = curNodes[7];
+              isOk = true;
+            }
+            if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
+              uniqueNodes[0] = curNodes[0];
+              uniqueNodes[1] = curNodes[1];
+              uniqueNodes[2] = curNodes[2];
+              uniqueNodes[3] = curNodes[4];
+              uniqueNodes[4] = curNodes[5];
+              uniqueNodes[5] = curNodes[6];
+              isOk = true;
+            }
+            if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
+              uniqueNodes[0] = curNodes[1];
+              uniqueNodes[1] = curNodes[2];
+              uniqueNodes[2] = curNodes[3];
+              uniqueNodes[3] = curNodes[5];
+              uniqueNodes[4] = curNodes[6];
+              uniqueNodes[5] = curNodes[0];
+              isOk = true;
+            }
+            if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
+              uniqueNodes[0] = curNodes[0];
+              uniqueNodes[1] = curNodes[1];
+              uniqueNodes[2] = curNodes[3];
+              uniqueNodes[3] = curNodes[4];
+              uniqueNodes[4] = curNodes[6];
+              uniqueNodes[5] = curNodes[7];
+              isOk = true;
+            }
+            if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
+              uniqueNodes[0] = curNodes[0];
+              uniqueNodes[1] = curNodes[2];
+              uniqueNodes[2] = curNodes[3];
+              uniqueNodes[3] = curNodes[1];
+              uniqueNodes[4] = curNodes[6];
+              uniqueNodes[5] = curNodes[7];
+              isOk = true;
+            }
+            if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
+              uniqueNodes[0] = curNodes[0];
+              uniqueNodes[1] = curNodes[1];
+              uniqueNodes[2] = curNodes[2];
+              uniqueNodes[3] = curNodes[4];
+              uniqueNodes[4] = curNodes[5];
+              uniqueNodes[5] = curNodes[7];
+              isOk = true;
+            }
+            if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
+              uniqueNodes[0] = curNodes[0];
+              uniqueNodes[1] = curNodes[1];
+              uniqueNodes[2] = curNodes[3];
+              uniqueNodes[3] = curNodes[4];
+              uniqueNodes[4] = curNodes[2];
+              uniqueNodes[5] = curNodes[7];
+              isOk = true;
+            }
+            if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
+              uniqueNodes[0] = curNodes[0];
+              uniqueNodes[1] = curNodes[1];
+              uniqueNodes[2] = curNodes[2];
+              uniqueNodes[3] = curNodes[4];
+              uniqueNodes[4] = curNodes[5];
+              uniqueNodes[5] = curNodes[3];
+              isOk = true;
+            }
+          }
+          break;
+        }
+        //////////////////////////////////// HEXAHEDRON
         isOk = false;
         SMDS_VolumeTool hexa (elem);
         hexa.SetExternalNormal();
@@ -3499,6 +4878,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
                                    curNodes[ind[ 3 ]],
                                    curNodes[ind[ 2 ]],
                                    curNodes[indTop[ 0 ]]);
+                myLastCreatedElems.Append(newElem);
                 if ( aShapeId )
                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
                 isOk = true;
@@ -3564,6 +4944,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
                                                          curNodes[ i2 ],
                                                          curNodes[ i3d ],
                                                          curNodes[ i2t ]);
+            myLastCreatedElems.Append(newElem);
             if ( aShapeId )
               aMesh->SetMeshElementOnShape( newElem, aShapeId );
             isOk = true;
@@ -3640,11 +5021,13 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
           }
           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
         }
-      } else {
+      }
+      else {
         // Change regular element or polygon
         aMesh->ChangeElementNodes( elem, uniqueNodes, nbUniqueNodes );
       }
-    } else {
+    }
+    else {
       // Remove invalid regular element or invalid polygon
       rmElemIds.push_back( elem->GetID() );
     }
@@ -3658,6 +5041,35 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 
 }
 
+
+// ========================================================
+// class   : SortableElement
+// purpose : allow sorting elements basing on their nodes
+// ========================================================
+class SortableElement : public set <const SMDS_MeshElement*>
+{
+ public:
+
+  SortableElement( const SMDS_MeshElement* theElem )
+    {
+      myElem = theElem;
+      SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
+      while ( nodeIt->more() )
+        this->insert( nodeIt->next() );
+    }
+
+  const SMDS_MeshElement* Get() const
+    { return myElem; }
+
+  void Set(const SMDS_MeshElement* e) const
+    { myElem = e; }
+
+
+ private:
+  mutable const SMDS_MeshElement* myElem;
+};
+
+
 //=======================================================================
 //function : MergeEqualElements
 //purpose  : Remove all but one of elements built on the same nodes.
@@ -3665,6 +5077,9 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 
 void SMESH_MeshEditor::MergeEqualElements()
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   SMESHDS_Mesh* aMesh = GetMeshDS();
 
   SMDS_EdgeIteratorPtr   eIt = aMesh->edgesIterator();
@@ -3675,8 +5090,7 @@ void SMESH_MeshEditor::MergeEqualElements()
 
   for ( int iDim = 1; iDim <= 3; iDim++ ) {
 
-    set< set <const SMDS_MeshElement*> > setOfNodeSet;
-
+    set< SortableElement > setOfNodeSet;
     while ( 1 ) {
       // get next element
       const SMDS_MeshElement* elem = 0;
@@ -3689,16 +5103,25 @@ void SMESH_MeshEditor::MergeEqualElements()
       }
       if ( !elem ) break;
 
-      // get elem nodes
-      set <const SMDS_MeshElement*> nodeSet;
-      SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
-      while ( nodeIt->more() )
-        nodeSet.insert( nodeIt->next() );
+      SortableElement SE(elem);
 
       // check uniqueness
-      bool isUnique = setOfNodeSet.insert( nodeSet ).second;
-      if ( !isUnique )
-        rmElemIds.push_back( elem->GetID() );
+      pair< set<SortableElement>::iterator, bool> pp = setOfNodeSet.insert(SE);
+      if( !(pp.second) ) {
+        set<SortableElement>::iterator & itSE = pp.first;
+        const SortableElement & SEold = *itSE;
+        if( SEold.Get()->GetID() > elem->GetID() ) {
+          // keep elem, remove old
+          rmElemIds.push_back( SEold.Get()->GetID() );
+          // add kept elem in groups of removed one (PAL15188)
+          AddToSameGroups( elem, SEold.Get(), GetMeshDS() );
+          SEold.Set( elem );
+        }
+          else { // remove elem
+          rmElemIds.push_back( elem->GetID() );
+          AddToSameGroups( SEold.Get(), elem, GetMeshDS() );
+        }
+      }
     }
   }
 
@@ -3713,17 +5136,16 @@ void SMESH_MeshEditor::MergeEqualElements()
 //=======================================================================
 
 const SMDS_MeshElement*
-  SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*                n1,
-                                  const SMDS_MeshNode*                n2,
-                                  const set<const SMDS_MeshElement*>& elemSet,
-                                  const set<const SMDS_MeshElement*>& avoidSet)
+  SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
+                                  const SMDS_MeshNode*    n2,
+                                  const TIDSortedElemSet& elemSet,
+                                  const TIDSortedElemSet& avoidSet)
 
 {
-  SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator();
+  SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
   while ( invElemIt->more() ) { // loop on inverse elements of n1
     const SMDS_MeshElement* elem = invElemIt->next();
-    if (elem->GetType() != SMDSAbs_Face ||
-        avoidSet.find( elem ) != avoidSet.end() )
+    if (avoidSet.find( elem ) != avoidSet.end() )
       continue;
     if ( !elemSet.empty() && elemSet.find( elem ) == elemSet.end())
       continue;
@@ -3737,14 +5159,53 @@ const SMDS_MeshElement*
         i1 = iNode - 1;
     }
     // find a n2 linked to n1
-    for ( iNode = 0; iNode < 2; iNode++ ) {
-      if ( iNode ) // node before n1
-        n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
-      else         // node after n1
-        n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
-      if ( n == n2 )
-        return elem;
+    if(!elem->IsQuadratic()) {
+      for ( iNode = 0; iNode < 2; iNode++ ) {
+        if ( iNode ) // node before n1
+          n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
+        else         // node after n1
+          n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
+        if ( n == n2 )
+          return elem;
+      }
     }
+    else { // analysis for quadratic elements
+      bool IsFind = false;
+      // check using only corner nodes
+      for ( iNode = 0; iNode < 2; iNode++ ) {
+        if ( iNode ) // node before n1
+          n = faceNodes[ i1 == 0 ? nbN/2 - 1 : i1 - 1 ];
+        else         // node after n1
+          n = faceNodes[ i1 + 1 == nbN/2 ? 0 : i1 + 1 ];
+        if ( n == n2 )
+          IsFind = true;
+      }
+      if(IsFind) {
+        return elem;
+      }
+      else {
+        // check using all nodes
+        const SMDS_QuadraticFaceOfNodes* F =
+          static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
+        // use special nodes iterator
+        iNode = 0;
+        SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+        while ( anIter->more() ) {
+          faceNodes[iNode] = static_cast<const SMDS_MeshNode*>(anIter->next());
+          if ( faceNodes[ iNode++ ] == n1 )
+            i1 = iNode - 1;
+        }
+        for ( iNode = 0; iNode < 2; iNode++ ) {
+          if ( iNode ) // node before n1
+            n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
+          else         // node after n1
+            n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
+          if ( n == n2 ) {
+            return elem;
+          }
+        }
+      }
+    } // end analysis for quadratic elements
   }
   return 0;
 }
@@ -3758,24 +5219,24 @@ static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
                                                 const SMDS_MeshNode* n2,
                                                 const SMDS_MeshElement* elem)
 {
-  set<const SMDS_MeshElement*> elemSet, avoidSet;
+  TIDSortedElemSet elemSet, avoidSet;
   if ( elem )
     avoidSet.insert ( elem );
   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
 }
 
 //=======================================================================
-//function : findFreeBorder
+//function : FindFreeBorder
 //purpose  :
 //=======================================================================
 
 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
 
-static bool findFreeBorder (const SMDS_MeshNode*                theFirstNode,
-                            const SMDS_MeshNode*                theSecondNode,
-                            const SMDS_MeshNode*                theLastNode,
-                            list< const SMDS_MeshNode* > &      theNodes,
-                            list< const SMDS_MeshElement* > &   theFaces)
+bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
+                                       const SMDS_MeshNode*             theSecondNode,
+                                       const SMDS_MeshNode*             theLastNode,
+                                       list< const SMDS_MeshNode* > &   theNodes,
+                                       list< const SMDS_MeshElement* >& theFaces)
 {
   if ( !theFirstNode || !theSecondNode )
     return false;
@@ -3788,12 +5249,12 @@ static bool findFreeBorder (const SMDS_MeshNode*                theFirstNode,
   theNodes.push_back( theFirstNode );
   theNodes.push_back( theSecondNode );
 
-  const SMDS_MeshNode* nodes [5], *nIgnore = theFirstNode, * nStart = theSecondNode;
+  //vector<const SMDS_MeshNode*> nodes;
+  const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
   set < const SMDS_MeshElement* > foundElems;
   bool needTheLast = ( theLastNode != 0 );
 
-  while ( nStart != theLastNode )
-  {
+  while ( nStart != theLastNode ) {
     if ( nStart == theFirstNode )
       return !needTheLast;
 
@@ -3801,16 +5262,27 @@ static bool findFreeBorder (const SMDS_MeshNode*                theFirstNode,
 
     list< const SMDS_MeshElement* > curElemList;
     list< const SMDS_MeshNode* > nStartList;
-    SMDS_ElemIteratorPtr invElemIt = nStart->facesIterator();
+    SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
     while ( invElemIt->more() ) {
       const SMDS_MeshElement* e = invElemIt->next();
-      if ( e == curElem || foundElems.insert( e ).second )
-      {
+      if ( e == curElem || foundElems.insert( e ).second ) {
         // get nodes
-        SMDS_ElemIteratorPtr nIt = e->nodesIterator();
         int iNode = 0, nbNodes = e->NbNodes();
-        while ( nIt->more() )
-          nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
+        const SMDS_MeshNode* nodes[nbNodes+1];
+        if(e->IsQuadratic()) {
+          const SMDS_QuadraticFaceOfNodes* F =
+            static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
+          // use special nodes iterator
+          SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+          while( anIter->more() ) {
+            nodes[ iNode++ ] = anIter->next();
+          }
+        }
+        else {
+          SMDS_ElemIteratorPtr nIt = e->nodesIterator();
+          while ( nIt->more() )
+            nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
+        }
         nodes[ iNode ] = nodes[ 0 ];
         // check 2 links
         for ( iNode = 0; iNode < nbNodes; iNode++ )
@@ -3863,7 +5335,7 @@ static bool findFreeBorder (const SMDS_MeshNode*                theFirstNode,
         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
         // find one more free border
-        if ( ! findFreeBorder( nIgnore, nStart, theLastNode, *cNL, *cFL )) {
+        if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
           cNL->clear();
           cFL->clear();
         }
@@ -3907,7 +5379,7 @@ bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
 {
   list< const SMDS_MeshNode* > nodes;
   list< const SMDS_MeshElement* > faces;
-  return findFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
+  return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
 }
 
 //=======================================================================
@@ -3926,6 +5398,9 @@ SMESH_MeshEditor::Sew_Error
                                    const bool           toCreatePolygons,
                                    const bool           toCreatePolyedrs)
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   MESSAGE("::SewFreeBorder()");
   Sew_Error aResult = SEW_OK;
 
@@ -3940,16 +5415,15 @@ SMESH_MeshEditor::Sew_Error
 
   // Free border 1
   // --------------
-  if (!findFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
+  if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
                       nSide[0], eSide[0])) {
     MESSAGE(" Free Border 1 not found " );
     aResult = SEW_BORDER1_NOT_FOUND;
   }
-  if (theSideIsFreeBorder)
-  {
+  if (theSideIsFreeBorder) {
     // Free border 2
     // --------------
-    if (!findFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
+    if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
                         nSide[1], eSide[1])) {
       MESSAGE(" Free Border 2 not found " );
       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
@@ -3958,8 +5432,7 @@ SMESH_MeshEditor::Sew_Error
   if ( aResult != SEW_OK )
     return aResult;
 
-  if (!theSideIsFreeBorder)
-  {
+  if (!theSideIsFreeBorder) {
     // Side 2
     // --------------
 
@@ -3985,8 +5458,7 @@ SMESH_MeshEditor::Sew_Error
     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
     double tol2 = 1.e-8;
     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
-    if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 )
-    {
+    if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
       // Need node movement.
 
       // find X and Z axes to create trsf
@@ -4015,8 +5487,7 @@ SMESH_MeshEditor::Sew_Error
         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
       }
     }
-    else
-    {
+    else {
       // just insert nodes XYZ in the nBordXYZ map
       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
         const SMDS_MeshNode* n = *nBordIt;
@@ -4057,24 +5528,39 @@ SMESH_MeshEditor::Sew_Error
       checkedLinkIDs.clear();
       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
 
-      SMDS_ElemIteratorPtr invElemIt
-        = prevSideNode->GetInverseElementIterator();
-      while ( invElemIt->more() ) { // loop on inverse elements on the Side 2
+      // loop on inverse elements of current node (prevSideNode) on the Side 2
+      SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
+      while ( invElemIt->more() )
+      {
         const SMDS_MeshElement* elem = invElemIt->next();
-        // prepare data for a loop on links, of a face or a volume
+        // prepare data for a loop on links coming to prevSideNode, of a face or a volume
         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
         const SMDS_MeshNode* faceNodes[ nbNodes ];
         bool isVolume = volume.Set( elem );
         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : faceNodes;
         if ( isVolume ) // --volume
           hasVolumes = true;
-        else if ( nbNodes > 2 ) { // --face
+        //else if ( nbNodes > 2 ) { // --face
+        else if ( elem->GetType()==SMDSAbs_Face ) { // --face
           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
-          SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
-          while ( nIt->more() ) {
-            nodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
-            if ( nodes[ iNode++ ] == prevSideNode )
-              iPrevNode = iNode - 1;
+          if(elem->IsQuadratic()) {
+            const SMDS_QuadraticFaceOfNodes* F =
+              static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
+            // use special nodes iterator
+            SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+            while( anIter->more() ) {
+              nodes[ iNode ] = anIter->next();
+              if ( nodes[ iNode++ ] == prevSideNode )
+                iPrevNode = iNode - 1;
+            }
+          }
+          else {
+            SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
+            while ( nIt->more() ) {
+              nodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
+              if ( nodes[ iNode++ ] == prevSideNode )
+                iPrevNode = iNode - 1;
+            }
           }
           // there are 2 links to check
           nbNodes = 2;
@@ -4087,7 +5573,8 @@ SMESH_MeshEditor::Sew_Error
           if ( isVolume ) {
             if ( !volume.IsLinked( n, prevSideNode ))
               continue;
-          } else {
+          }
+          else {
             if ( iNode ) // a node before prevSideNode
               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
             else         // a node after prevSideNode
@@ -4097,7 +5584,8 @@ SMESH_MeshEditor::Sew_Error
           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
           if (!isJustChecked &&
-              foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() ) {
+              foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
+          {
             // test a link geometrically
             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
             bool linkIsBetter = false;
@@ -4136,6 +5624,7 @@ SMESH_MeshEditor::Sew_Error
         // find the next border link to compare with
         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
+        // move to next border node if sideNode is before forward border node (bordPos)
         while ( *nBordIt != theBordLastNode && !searchByDir ) {
           prevBordNode = *nBordIt;
           nBordIt++;
@@ -4366,18 +5855,39 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
   int iNode = 0, il1, il2, i3, i4;
   il1 = il2 = i3 = i4 = -1;
   const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
-  SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
-  while ( nodeIt->more() ) {
-    const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
-    if ( n == theBetweenNode1 )
-      il1 = iNode;
-    else if ( n == theBetweenNode2 )
-      il2 = iNode;
-    else if ( i3 < 0 )
-      i3 = iNode;
-    else
-      i4 = iNode;
-    nodes[ iNode++ ] = n;
+
+  if(theFace->IsQuadratic()) {
+    const SMDS_QuadraticFaceOfNodes* F =
+      static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
+    // use special nodes iterator
+    SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+    while( anIter->more() ) {
+      const SMDS_MeshNode* n = anIter->next();
+      if ( n == theBetweenNode1 )
+        il1 = iNode;
+      else if ( n == theBetweenNode2 )
+        il2 = iNode;
+      else if ( i3 < 0 )
+        i3 = iNode;
+      else
+        i4 = iNode;
+      nodes[ iNode++ ] = n;
+    }
+  }
+  else {
+    SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
+    while ( nodeIt->more() ) {
+      const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
+      if ( n == theBetweenNode1 )
+        il1 = iNode;
+      else if ( n == theBetweenNode2 )
+        il2 = iNode;
+      else if ( i3 < 0 )
+        i3 = iNode;
+      else
+        i4 = iNode;
+      nodes[ iNode++ ] = n;
+    }
   }
   if ( il1 < 0 || il2 < 0 || i3 < 0 )
     return ;
@@ -4406,25 +5916,48 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
 
     // add nodes of face up to first node of link
     bool isFLN = false;
-    nodeIt = theFace->nodesIterator();
-    while ( nodeIt->more() && !isFLN ) {
-      const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
-      poly_nodes[iNode++] = n;
-      if (n == nodes[il1]) {
-        isFLN = true;
-      }
-    }
 
-    // add nodes to insert
-    list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
-    for (; nIt != aNodesToInsert.end(); nIt++) {
-      poly_nodes[iNode++] = *nIt;
+    if(theFace->IsQuadratic()) {
+      const SMDS_QuadraticFaceOfNodes* F =
+        static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
+      // use special nodes iterator
+      SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+      while( anIter->more()  && !isFLN ) {
+        const SMDS_MeshNode* n = anIter->next();
+        poly_nodes[iNode++] = n;
+        if (n == nodes[il1]) {
+          isFLN = true;
+        }
+      }
+      // add nodes to insert
+      list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
+      for (; nIt != aNodesToInsert.end(); nIt++) {
+        poly_nodes[iNode++] = *nIt;
+      }
+      // add nodes of face starting from last node of link
+      while ( anIter->more() ) {
+        poly_nodes[iNode++] = anIter->next();
+      }
     }
-
-    // add nodes of face starting from last node of link
-    while ( nodeIt->more() ) {
-      const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
-      poly_nodes[iNode++] = n;
+    else {
+      SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
+      while ( nodeIt->more() && !isFLN ) {
+        const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
+        poly_nodes[iNode++] = n;
+        if (n == nodes[il1]) {
+          isFLN = true;
+        }
+      }
+      // add nodes to insert
+      list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
+      for (; nIt != aNodesToInsert.end(); nIt++) {
+        poly_nodes[iNode++] = *nIt;
+      }
+      // add nodes of face starting from last node of link
+      while ( nodeIt->more() ) {
+        const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
+        poly_nodes[iNode++] = n;
+      }
     }
 
     // edit or replace the face
@@ -4432,11 +5965,12 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
 
     if (theFace->IsPoly()) {
       aMesh->ChangePolygonNodes(theFace, poly_nodes);
-
-    else {
+    }
+    else {
       int aShapeId = FindShape( theFace );
 
       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
+      myLastCreatedElems.Append(newElem);
       if ( aShapeId && newElem )
         aMesh->SetMeshElementOnShape( newElem, aShapeId );
 
@@ -4445,81 +5979,194 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
     return;
   }
 
-  // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
-  int nbLinkNodes = 2 + aNodesToInsert.size();
-  const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
-  linkNodes[ 0 ] = nodes[ il1 ];
-  linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
-  list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
-  for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
-    linkNodes[ iNode++ ] = *nIt;
-  }
-  // decide how to split a quadrangle: compare possible variants
-  // and choose which of splits to be a quadrangle
-  int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
-  if ( nbFaceNodes == 3 )
-  {
-    iBestQuad = nbSplits;
-    i4 = i3;
-  }
-  else if ( nbFaceNodes == 4 )
-  {
-    SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
-    double aBestRate = DBL_MAX;
-    for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
-      i1 = 0; i2 = 1;
-      double aBadRate = 0;
-      // evaluate elements quality
-      for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
-        if ( iSplit == iQuad ) {
-          SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
-                                 linkNodes[ i2++ ],
-                                 nodes[ i3 ],
-                                 nodes[ i4 ]);
-          aBadRate += getBadRate( &quad, aCrit );
+  if( !theFace->IsQuadratic() ) {
+
+    // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
+    int nbLinkNodes = 2 + aNodesToInsert.size();
+    const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
+    linkNodes[ 0 ] = nodes[ il1 ];
+    linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
+    list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
+    for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
+      linkNodes[ iNode++ ] = *nIt;
+    }
+    // decide how to split a quadrangle: compare possible variants
+    // and choose which of splits to be a quadrangle
+    int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
+    if ( nbFaceNodes == 3 ) {
+      iBestQuad = nbSplits;
+      i4 = i3;
+    }
+    else if ( nbFaceNodes == 4 ) {
+      SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
+      double aBestRate = DBL_MAX;
+      for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
+        i1 = 0; i2 = 1;
+        double aBadRate = 0;
+        // evaluate elements quality
+        for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
+          if ( iSplit == iQuad ) {
+            SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
+                                   linkNodes[ i2++ ],
+                                   nodes[ i3 ],
+                                   nodes[ i4 ]);
+            aBadRate += getBadRate( &quad, aCrit );
+          }
+          else {
+            SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
+                                   linkNodes[ i2++ ],
+                                   nodes[ iSplit < iQuad ? i4 : i3 ]);
+            aBadRate += getBadRate( &tria, aCrit );
+          }
         }
-        else {
-          SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
-                                 linkNodes[ i2++ ],
-                                 nodes[ iSplit < iQuad ? i4 : i3 ]);
-          aBadRate += getBadRate( &tria, aCrit );
+        // choice
+        if ( aBadRate < aBestRate ) {
+          iBestQuad = iQuad;
+          aBestRate = aBadRate;
         }
       }
-      // choice
-      if ( aBadRate < aBestRate ) {
-        iBestQuad = iQuad;
-        aBestRate = aBadRate;
-      }
     }
-  }
 
-  // create new elements
-  SMESHDS_Mesh *aMesh = GetMeshDS();
-  int aShapeId = FindShape( theFace );
-
-  i1 = 0; i2 = 1;
-  for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
-    SMDS_MeshElement* newElem = 0;
-    if ( iSplit == iBestQuad )
-      newElem = aMesh->AddFace (linkNodes[ i1++ ],
-                                linkNodes[ i2++ ],
-                                nodes[ i3 ],
-                                nodes[ i4 ]);
-    else
-      newElem = aMesh->AddFace (linkNodes[ i1++ ],
-                                linkNodes[ i2++ ],
-                                nodes[ iSplit < iBestQuad ? i4 : i3 ]);
-    if ( aShapeId && newElem )
-      aMesh->SetMeshElementOnShape( newElem, aShapeId );
-  }
+    // create new elements
+    SMESHDS_Mesh *aMesh = GetMeshDS();
+    int aShapeId = FindShape( theFace );
+
+    i1 = 0; i2 = 1;
+    for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
+      SMDS_MeshElement* newElem = 0;
+      if ( iSplit == iBestQuad )
+        newElem = aMesh->AddFace (linkNodes[ i1++ ],
+                                  linkNodes[ i2++ ],
+                                  nodes[ i3 ],
+                                  nodes[ i4 ]);
+      else
+        newElem = aMesh->AddFace (linkNodes[ i1++ ],
+                                  linkNodes[ i2++ ],
+                                  nodes[ iSplit < iBestQuad ? i4 : i3 ]);
+      myLastCreatedElems.Append(newElem);
+      if ( aShapeId && newElem )
+        aMesh->SetMeshElementOnShape( newElem, aShapeId );
+    }
 
-  // change nodes of theFace
-  const SMDS_MeshNode* newNodes[ 4 ];
-  newNodes[ 0 ] = linkNodes[ i1 ];
-  newNodes[ 1 ] = linkNodes[ i2 ];
-  newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
-  newNodes[ 3 ] = nodes[ i4 ];
-  aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
+    // change nodes of theFace
+    const SMDS_MeshNode* newNodes[ 4 ];
+    newNodes[ 0 ] = linkNodes[ i1 ];
+    newNodes[ 1 ] = linkNodes[ i2 ];
+    newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
+    newNodes[ 3 ] = nodes[ i4 ];
+    aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
+  } // end if(!theFace->IsQuadratic())
+  else { // theFace is quadratic
+    // we have to split theFace on simple triangles and one simple quadrangle
+    int tmp = il1/2;
+    int nbshift = tmp*2;
+    // shift nodes in nodes[] by nbshift
+    int i,j;
+    for(i=0; i<nbshift; i++) {
+      const SMDS_MeshNode* n = nodes[0];
+      for(j=0; j<nbFaceNodes-1; j++) {
+        nodes[j] = nodes[j+1];
+      }
+      nodes[nbFaceNodes-1] = n;
+    }
+    il1 = il1 - nbshift;
+    // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
+    //   n0      n1     n2    n0      n1     n2
+    //     +-----+-----+        +-----+-----+
+    //      \         /         |           |
+    //       \       /          |           |
+    //      n5+     +n3       n7+           +n3
+    //         \   /            |           |
+    //          \ /             |           |
+    //           +              +-----+-----+
+    //           n4           n6      n5     n4
+
+    // create new elements
+    SMESHDS_Mesh *aMesh = GetMeshDS();
+    int aShapeId = FindShape( theFace );
+
+    int n1,n2,n3;
+    if(nbFaceNodes==6) { // quadratic triangle
+      SMDS_MeshElement* newElem =
+        aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
+      myLastCreatedElems.Append(newElem);
+      if ( aShapeId && newElem )
+        aMesh->SetMeshElementOnShape( newElem, aShapeId );
+      if(theFace->IsMediumNode(nodes[il1])) {
+        // create quadrangle
+        newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
+        myLastCreatedElems.Append(newElem);
+        if ( aShapeId && newElem )
+          aMesh->SetMeshElementOnShape( newElem, aShapeId );
+        n1 = 1;
+        n2 = 2;
+        n3 = 3;
+      }
+      else {
+        // create quadrangle
+        newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
+        myLastCreatedElems.Append(newElem);
+        if ( aShapeId && newElem )
+          aMesh->SetMeshElementOnShape( newElem, aShapeId );
+        n1 = 0;
+        n2 = 1;
+        n3 = 5;
+      }
+    }
+    else { // nbFaceNodes==8 - quadratic quadrangle
+      SMDS_MeshElement* newElem =
+        aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
+      myLastCreatedElems.Append(newElem);
+      if ( aShapeId && newElem )
+        aMesh->SetMeshElementOnShape( newElem, aShapeId );
+      newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
+      myLastCreatedElems.Append(newElem);
+      if ( aShapeId && newElem )
+        aMesh->SetMeshElementOnShape( newElem, aShapeId );
+      newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
+      myLastCreatedElems.Append(newElem);
+      if ( aShapeId && newElem )
+        aMesh->SetMeshElementOnShape( newElem, aShapeId );
+      if(theFace->IsMediumNode(nodes[il1])) {
+        // create quadrangle
+        newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
+        myLastCreatedElems.Append(newElem);
+        if ( aShapeId && newElem )
+          aMesh->SetMeshElementOnShape( newElem, aShapeId );
+        n1 = 1;
+        n2 = 2;
+        n3 = 3;
+      }
+      else {
+        // create quadrangle
+        newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
+        myLastCreatedElems.Append(newElem);
+        if ( aShapeId && newElem )
+          aMesh->SetMeshElementOnShape( newElem, aShapeId );
+        n1 = 0;
+        n2 = 1;
+        n3 = 7;
+      }
+    }
+    // create needed triangles using n1,n2,n3 and inserted nodes
+    int nbn = 2 + aNodesToInsert.size();
+    const SMDS_MeshNode* aNodes[nbn];
+    aNodes[0] = nodes[n1];
+    aNodes[nbn-1] = nodes[n2];
+    list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
+    for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
+      aNodes[iNode++] = *nIt;
+    }
+    for(i=1; i<nbn; i++) {
+      SMDS_MeshElement* newElem =
+        aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
+      myLastCreatedElems.Append(newElem);
+      if ( aShapeId && newElem )
+        aMesh->SetMeshElementOnShape( newElem, aShapeId );
+    }
+    // remove old quadratic face
+    aMesh->RemoveElement(theFace);
+  }
 }
 
 //=======================================================================
@@ -4530,11 +6177,12 @@ void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode
                                       const SMDS_MeshNode*        theBetweenNode2,
                                       list<const SMDS_MeshNode*>& theNodesToInsert)
 {
-  SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator();
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
+  SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
     const SMDS_MeshElement* elem = invElemIt->next();
-    if (elem->GetType() != SMDSAbs_Volume)
-      continue;
 
     // check, if current volume has link theBetweenNode1 - theBetweenNode2
     SMDS_VolumeTool aVolume (elem);
@@ -4565,7 +6213,8 @@ void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode
                 poly_nodes.push_back(*nIt);
               }
             }
-          } else if (faceNodes[inode] == theBetweenNode2) {
+          }
+          else if (faceNodes[inode] == theBetweenNode2) {
             if (faceNodes[inode + 1] == theBetweenNode1) {
               nbInserted = theNodesToInsert.size();
 
@@ -4577,7 +6226,8 @@ void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode
               }
               poly_nodes.push_back(*nIt);
             }
-          } else {
+          }
+          else {
           }
         }
       }
@@ -4590,11 +6240,13 @@ void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode
     if (elem->IsPoly()) {
       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
 
-    } else {
+    }
+    else {
       int aShapeId = FindShape( elem );
 
       SMDS_MeshElement* newElem =
         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
+      myLastCreatedElems.Append(newElem);
       if (aShapeId && newElem)
         aMesh->SetMeshElementOnShape(newElem, aShapeId);
 
@@ -4603,19 +6255,327 @@ void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode
   }
 }
 
+//=======================================================================
+//function : ConvertElemToQuadratic
+//purpose  :
+//=======================================================================
+void SMESH_MeshEditor::ConvertElemToQuadratic(SMESHDS_SubMesh *   theSm,
+                                              SMESH_MesherHelper& theHelper,
+                                             const bool          theForce3d)
+{
+  if( !theSm ) return;
+  SMESHDS_Mesh* meshDS = GetMeshDS();
+  SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
+  while(ElemItr->more())
+  {
+    const SMDS_MeshElement* elem = ElemItr->next();
+    if( !elem || elem->IsQuadratic() ) continue;
+
+    int id = elem->GetID();
+    int nbNodes = elem->NbNodes();
+    vector<const SMDS_MeshNode *> aNds (nbNodes);
+
+    for(int i = 0; i < nbNodes; i++)
+    {
+      aNds[i] = elem->GetNode(i);
+    }
+    SMDSAbs_ElementType aType = elem->GetType();
+
+    theSm->RemoveElement(elem);
+    meshDS->SMDS_Mesh::RemoveFreeElement(elem);
+
+    const SMDS_MeshElement* NewElem = 0;
+
+    switch( aType )
+    {
+    case SMDSAbs_Edge :
+    {
+      NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
+      break;
+    }
+    case SMDSAbs_Face :
+    {
+      switch(nbNodes)
+      {
+      case 3:
+       NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
+       break;
+      case 4:
+       NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
+       break;
+      default:
+       continue;
+      }
+      break;
+    }
+    case SMDSAbs_Volume :
+    {
+      switch(nbNodes)
+      {
+      case 4:
+       NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, true);
+       break;
+      case 6:
+       NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, true);
+       break;
+      case 8:
+       NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
+                                      aNds[4], aNds[5], aNds[6], aNds[7], id, true);
+       break;
+      default:
+       continue;
+      }
+      break;
+    }
+    default :
+      continue;
+    }
+    if( NewElem )
+    {
+      AddToSameGroups( NewElem, elem, meshDS);
+      theSm->AddElement( NewElem );
+    }
+    if ( NewElem != elem )
+      RemoveElemFromGroups (elem, meshDS);
+  }
+}
+
+//=======================================================================
+//function : ConvertToQuadratic
+//purpose  :
+//=======================================================================
+void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
+{
+  SMESHDS_Mesh* meshDS = GetMeshDS();
+
+  SMESH_MesherHelper aHelper(*myMesh);
+  aHelper.SetIsQuadratic( true );
+  const TopoDS_Shape& aShape = meshDS->ShapeToMesh();
+
+  if ( !aShape.IsNull() && GetMesh()->GetSubMeshContaining(aShape) )
+  {
+    SMESH_subMesh *aSubMesh = GetMesh()->GetSubMeshContaining(aShape);
+
+    const map < int, SMESH_subMesh * >& aMapSM = aSubMesh->DependsOn();
+    map < int, SMESH_subMesh * >::const_iterator itsub;
+    for (itsub = aMapSM.begin(); itsub != aMapSM.end(); itsub++)
+    {
+      SMESHDS_SubMesh *sm = ((*itsub).second)->GetSubMeshDS();
+      aHelper.SetSubShape( (*itsub).second->GetSubShape() );
+      ConvertElemToQuadratic(sm, aHelper, theForce3d);
+    }
+    aHelper.SetSubShape( aSubMesh->GetSubShape() );
+    ConvertElemToQuadratic(aSubMesh->GetSubMeshDS(), aHelper, theForce3d);
+  }
+  else
+  {
+    SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
+    while(aEdgeItr->more())
+    {
+      const SMDS_MeshEdge* edge = aEdgeItr->next();
+      if(edge && !edge->IsQuadratic())
+      {
+       int id = edge->GetID();
+       const SMDS_MeshNode* n1 = edge->GetNode(0);
+       const SMDS_MeshNode* n2 = edge->GetNode(1);
+
+       meshDS->SMDS_Mesh::RemoveFreeElement(edge);
+
+        const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
+        if ( NewEdge )
+          AddToSameGroups(NewEdge, edge, meshDS);
+        if ( NewEdge != edge )
+          RemoveElemFromGroups (edge, meshDS);
+      }
+    }
+    SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
+    while(aFaceItr->more())
+    {
+      const SMDS_MeshFace* face = aFaceItr->next();
+      if(!face || face->IsQuadratic() ) continue;
+
+      int id = face->GetID();
+      int nbNodes = face->NbNodes();
+      vector<const SMDS_MeshNode *> aNds (nbNodes);
+
+      for(int i = 0; i < nbNodes; i++)
+      {
+       aNds[i] = face->GetNode(i);
+      }
+
+      meshDS->SMDS_Mesh::RemoveFreeElement(face);
+
+      SMDS_MeshFace * NewFace = 0;
+      switch(nbNodes)
+      {
+      case 3:
+       NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
+       break;
+      case 4:
+       NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
+       break;
+      default:
+       continue;
+      }
+      if ( NewFace )
+        AddToSameGroups(NewFace, face, meshDS);
+      if ( NewFace != face )
+        RemoveElemFromGroups (face, meshDS);
+    }
+    SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
+    while(aVolumeItr->more())
+    {
+      const SMDS_MeshVolume* volume = aVolumeItr->next();
+      if(!volume || volume->IsQuadratic() ) continue;
+
+      int id = volume->GetID();
+      int nbNodes = volume->NbNodes();
+      vector<const SMDS_MeshNode *> aNds (nbNodes);
+
+      for(int i = 0; i < nbNodes; i++)
+      {
+       aNds[i] = volume->GetNode(i);
+      }
+
+      meshDS->SMDS_Mesh::RemoveFreeElement(volume);
+
+      SMDS_MeshVolume * NewVolume = 0;
+      switch(nbNodes)
+      {
+      case 4:
+       NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
+                                      aNds[3], id, true );
+       break;
+      case 6:
+       NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
+                                      aNds[3], aNds[4], aNds[5], id, true);
+       break;
+      case 8:
+       NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
+                                      aNds[4], aNds[5], aNds[6], aNds[7], id, true);
+       break;
+      default:
+       continue;
+      }
+      if ( NewVolume )
+        AddToSameGroups(NewVolume, volume, meshDS);
+      if ( NewVolume != volume )
+        RemoveElemFromGroups (volume, meshDS);
+    }
+  }
+}
+
+//=======================================================================
+//function : RemoveQuadElem
+//purpose  :
+//=======================================================================
+void SMESH_MeshEditor::RemoveQuadElem(SMESHDS_SubMesh *    theSm,
+                                     SMDS_ElemIteratorPtr theItr,
+                                     const int            theShapeID)
+{
+  SMESHDS_Mesh* meshDS = GetMeshDS();
+  while( theItr->more() )
+  {
+    const SMDS_MeshElement* elem = theItr->next();
+    if( elem && elem->IsQuadratic())
+    {
+      int id = elem->GetID();
+      int nbNodes = elem->NbNodes();
+      vector<const SMDS_MeshNode *> aNds, mediumNodes;
+      aNds.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
+         aNds.push_back( n );
+      }
+      if( aNds.empty() ) continue;
+      SMDSAbs_ElementType aType = elem->GetType();
+
+      //remove old quadratic elements
+      meshDS->SMDS_Mesh::RemoveFreeElement( elem );
+      if ( theSm )
+        theSm->RemoveElement( elem );
+
+      SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
+      if ( NewElem )
+        AddToSameGroups(NewElem, elem, meshDS);
+      if ( NewElem != elem )
+        RemoveElemFromGroups (elem, meshDS);
+      if( theSm && NewElem )
+       theSm->AddElement( NewElem );
+
+      // remove medium nodes
+      vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
+      for ( ; nIt != mediumNodes.end(); ++nIt ) {
+        const SMDS_MeshNode* n = *nIt;
+        if ( n->NbInverseNodes() == 0 ) {
+          if ( n->GetPosition()->GetShapeId() != theShapeID )
+            meshDS->RemoveFreeNode( n, meshDS->MeshElements
+                                    ( n->GetPosition()->GetShapeId() ));
+          else
+            meshDS->RemoveFreeNode( n, theSm );
+       }
+      }
+    }
+  }
+}
+
+//=======================================================================
+//function : ConvertFromQuadratic
+//purpose  :
+//=======================================================================
+bool  SMESH_MeshEditor::ConvertFromQuadratic()
+{
+  SMESHDS_Mesh* meshDS = GetMeshDS();
+  const TopoDS_Shape& aShape = meshDS->ShapeToMesh();
+
+  if ( !aShape.IsNull() && GetMesh()->GetSubMeshContaining(aShape) )
+  {
+    SMESH_subMesh *aSubMesh = GetMesh()->GetSubMeshContaining(aShape);
+
+    const map < int, SMESH_subMesh * >& aMapSM = aSubMesh->DependsOn();
+    map < int, SMESH_subMesh * >::const_iterator itsub;
+    for (itsub = aMapSM.begin(); itsub != aMapSM.end(); itsub++)
+    {
+      SMESHDS_SubMesh *sm = ((*itsub).second)->GetSubMeshDS();
+      if( sm )
+       RemoveQuadElem( sm, sm->GetElements(), itsub->second->GetId() );
+    }
+    SMESHDS_SubMesh *Sm = aSubMesh->GetSubMeshDS();
+    if( Sm )
+      RemoveQuadElem( Sm, Sm->GetElements(), aSubMesh->GetId() );
+  }
+  else
+  {
+    SMESHDS_SubMesh *aSM = 0;
+    RemoveQuadElem( aSM, meshDS->elementsIterator(), 0 );
+  }
+
+  return true;
+}
+
 //=======================================================================
 //function : SewSideElements
 //purpose  :
 //=======================================================================
 
 SMESH_MeshEditor::Sew_Error
-  SMESH_MeshEditor::SewSideElements (set<const SMDS_MeshElement*>& theSide1,
-                                     set<const SMDS_MeshElement*>& theSide2,
-                                     const SMDS_MeshNode*          theFirstNode1,
-                                     const SMDS_MeshNode*          theFirstNode2,
-                                     const SMDS_MeshNode*          theSecondNode1,
-                                     const SMDS_MeshNode*          theSecondNode2)
+  SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
+                                     TIDSortedElemSet&    theSide2,
+                                     const SMDS_MeshNode* theFirstNode1,
+                                     const SMDS_MeshNode* theFirstNode2,
+                                     const SMDS_MeshNode* theSecondNode1,
+                                     const SMDS_MeshNode* theSecondNode2)
 {
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
   MESSAGE ("::::SewSideElements()");
   if ( theSide1.size() != theSide2.size() )
     return SEW_DIFF_NB_OF_ELEMENTS;
@@ -4642,27 +6602,44 @@ SMESH_MeshEditor::Sew_Error
   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
-  set<const SMDS_MeshElement*> * elemSetPtr[] = { &theSide1, &theSide2 };
+  TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
   int iSide, iFace, iNode;
 
   for ( iSide = 0; iSide < 2; iSide++ ) {
     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
-    set<const SMDS_MeshElement*> * elemSet = elemSetPtr[ iSide ];
+    TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
-    set<const SMDS_MeshElement*>::iterator vIt, eIt;
+    set<const SMDS_MeshElement*>::iterator vIt;
+    TIDSortedElemSet::iterator eIt;
     set<const SMDS_MeshNode*>::iterator    nIt;
 
-  // -----------------------------------------------------------
-  // 1a. Collect nodes of existing faces
-  //     and build set of face nodes in order to detect missing
-  //     faces corresponing to sides of volumes
-  // -----------------------------------------------------------
+    // check that given nodes belong to given elements
+    const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
+    const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
+    int firstIndex = -1, secondIndex = -1;
+    for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
+      const SMDS_MeshElement* elem = *eIt;
+      if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
+      if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
+      if ( firstIndex > -1 && secondIndex > -1 ) break;
+    }
+    if ( firstIndex < 0 || secondIndex < 0 ) {
+      // we can simply return until temporary faces created
+      return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
+    }
+
+    // -----------------------------------------------------------
+    // 1a. Collect nodes of existing faces
+    //     and build set of face nodes in order to detect missing
+    //     faces corresponing to sides of volumes
+    // -----------------------------------------------------------
 
     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
 
     // loop on the given element of a side
     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
+      //const SMDS_MeshElement* elem = *eIt;
       const SMDS_MeshElement* elem = *eIt;
       if ( elem->GetType() == SMDSAbs_Face ) {
         faceSet->insert( elem );
@@ -4683,7 +6660,7 @@ SMESH_MeshEditor::Sew_Error
     // ------------------------------------------------------------------------------
 
     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
-      SMDS_ElemIteratorPtr fIt = (*nIt)->facesIterator();
+      SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
       while ( fIt->more() ) { // loop on faces sharing a node
         const SMDS_MeshElement* f = fIt->next();
         if ( faceSet->find( f ) == faceSet->end() ) {
@@ -4712,8 +6689,7 @@ SMESH_MeshEditor::Sew_Error
     //     face does not exist
     // -------------------------------------------------------------------------
 
-    if ( !volSet->empty() )
-    {
+    if ( !volSet->empty() ) {
       //int nodeSetSize = nodeSet->size();
 
       // loop on given volumes
@@ -4736,13 +6712,12 @@ SMESH_MeshEditor::Sew_Error
             // no such a face is given but it still can exist, check it
             if ( nbNodes == 3 ) {
               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
-            } else if ( nbNodes == 4 ) {
+            }
+            else if ( nbNodes == 4 ) {
               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
-            } else {
-              vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
-              for (int inode = 0; inode < nbNodes; inode++) {
-                poly_nodes[inode] = fNodes[inode];
-              }
+            }
+            else {
+              vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
               aFreeFace = aMesh->FindFace(poly_nodes);
             }
           }
@@ -4750,13 +6725,12 @@ SMESH_MeshEditor::Sew_Error
             // create a temporary face
             if ( nbNodes == 3 ) {
               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
-            } else if ( nbNodes == 4 ) {
+            }
+            else if ( nbNodes == 4 ) {
               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
-            } else {
-              vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
-              for (int inode = 0; inode < nbNodes; inode++) {
-                poly_nodes[inode] = fNodes[inode];
-              }
+            }
+            else {
+              vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
               aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
             }
           }
@@ -4799,7 +6773,7 @@ SMESH_MeshEditor::Sew_Error
             // choose a face most close to the bary center of the opposite side
             gp_XYZ aBC( 0., 0., 0. );
             set <const SMDS_MeshNode*> addedNodes;
-            set<const SMDS_MeshElement*> * elemSet2 = elemSetPtr[ 1 - iSide ];
+            TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
             eIt = elemSet2->begin();
             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
@@ -4846,7 +6820,7 @@ SMESH_MeshEditor::Sew_Error
 //       // ----------------------------------------------------------
 //       if ( nodeSetSize != nodeSet->size() ) {
 //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
-//           SMDS_ElemIteratorPtr fIt = (*nIt)->facesIterator();
+//           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
 //           while ( fIt->more() ) { // loop on faces sharing a node
 //             const SMDS_MeshElement* f = fIt->next();
 //             if ( faceSet->find( f ) == faceSet->end() ) {
@@ -4897,16 +6871,15 @@ SMESH_MeshEditor::Sew_Error
   set< long > linkIdSet; // links to process
   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
 
-  typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > TPairOfNodes;
-  list< TPairOfNodes > linkList[2];
-  linkList[0].push_back( TPairOfNodes( theFirstNode1, theSecondNode1 ));
-  linkList[1].push_back( TPairOfNodes( theFirstNode2, theSecondNode2 ));
+  typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
+  list< NLink > linkList[2];
+  linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
+  linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
   // loop on links in linkList; find faces by links and append links
   // of the found faces to linkList
-  list< TPairOfNodes >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
-  for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
-  {
-    TPairOfNodes link[] = { *linkIt[0], *linkIt[1] };
+  list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
+  for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
+    NLink link[] = { *linkIt[0], *linkIt[1] };
     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
       continue;
@@ -4917,8 +6890,12 @@ SMESH_MeshEditor::Sew_Error
     // ---------------------------------------------------------------
 
     const SMDS_MeshElement* face[] = { 0, 0 };
-    const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
-    const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
+    //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
+    vector<const SMDS_MeshNode*> fnodes1(9);
+    vector<const SMDS_MeshNode*> fnodes2(9);
+    //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
+    vector<const SMDS_MeshNode*> notLinkNodes1(6);
+    vector<const SMDS_MeshNode*> notLinkNodes2(6);
     int iLinkNode[2][2];
     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
       const SMDS_MeshNode* n1 = link[iSide].first;
@@ -4927,7 +6904,7 @@ SMESH_MeshEditor::Sew_Error
       set< const SMDS_MeshElement* > fMap;
       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
-        SMDS_ElemIteratorPtr fIt = n->facesIterator();
+        SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
         while ( fIt->more() ) { // loop on faces sharing a node
           const SMDS_MeshElement* f = fIt->next();
           if (faceSet->find( f ) != faceSet->end() && // f is in face set
@@ -4942,40 +6919,109 @@ SMESH_MeshEditor::Sew_Error
             faceSet->erase( f );
             // get face nodes and find ones of a link
             iNode = 0;
-            SMDS_ElemIteratorPtr nIt = f->nodesIterator();
-            while ( nIt->more() ) {
-              const SMDS_MeshNode* n =
-                static_cast<const SMDS_MeshNode*>( nIt->next() );
-              if ( n == n1 )
-                iLinkNode[ iSide ][ 0 ] = iNode;
-              else if ( n == n2 )
-                iLinkNode[ iSide ][ 1 ] = iNode;
-              else if ( notLinkNodes[ iSide ][ 0 ] )
-                notLinkNodes[ iSide ][ 1 ] = n;
-              else
-                notLinkNodes[ iSide ][ 0 ] = n;
-              faceNodes[ iSide ][ iNode++ ] = n;
+            int nbl = -1;
+            if(f->IsPoly()) {
+              if(iSide==0) {
+                fnodes1.resize(f->NbNodes()+1);
+                notLinkNodes1.resize(f->NbNodes()-2);
+              }
+              else {
+                fnodes2.resize(f->NbNodes()+1);
+                notLinkNodes2.resize(f->NbNodes()-2);
+              }
+            }
+            if(!f->IsQuadratic()) {
+              SMDS_ElemIteratorPtr nIt = f->nodesIterator();
+              while ( nIt->more() ) {
+                const SMDS_MeshNode* n =
+                  static_cast<const SMDS_MeshNode*>( nIt->next() );
+                if ( n == n1 ) {
+                  iLinkNode[ iSide ][ 0 ] = iNode;
+                }
+                else if ( n == n2 ) {
+                  iLinkNode[ iSide ][ 1 ] = iNode;
+                }
+                //else if ( notLinkNodes[ iSide ][ 0 ] )
+                //  notLinkNodes[ iSide ][ 1 ] = n;
+                //else
+                //  notLinkNodes[ iSide ][ 0 ] = n;
+                else {
+                  nbl++;
+                  if(iSide==0)
+                    notLinkNodes1[nbl] = n;
+                    //notLinkNodes1.push_back(n);
+                  else
+                    notLinkNodes2[nbl] = n;
+                    //notLinkNodes2.push_back(n);
+                }
+                //faceNodes[ iSide ][ iNode++ ] = n;
+                if(iSide==0) {
+                  fnodes1[iNode++] = n;
+                }
+                else {
+                  fnodes2[iNode++] = n;
+                }
+              }
+            }
+            else { // f->IsQuadratic()
+              const SMDS_QuadraticFaceOfNodes* F =
+                static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
+              // use special nodes iterator
+              SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+              while ( anIter->more() ) {
+                const SMDS_MeshNode* n =
+                  static_cast<const SMDS_MeshNode*>( anIter->next() );
+                if ( n == n1 ) {
+                  iLinkNode[ iSide ][ 0 ] = iNode;
+                }
+                else if ( n == n2 ) {
+                  iLinkNode[ iSide ][ 1 ] = iNode;
+                }
+                else {
+                  nbl++;
+                  if(iSide==0) {
+                    notLinkNodes1[nbl] = n;
+                  }
+                  else {
+                    notLinkNodes2[nbl] = n;
+                  }
+                }
+                if(iSide==0) {
+                  fnodes1[iNode++] = n;
+                }
+                else {
+                  fnodes2[iNode++] = n;
+                }
+              }
+            }
+            //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
+            if(iSide==0) {
+              fnodes1[iNode] = fnodes1[0];
+            }
+            else {
+              fnodes2[iNode] = fnodes1[0];
             }
-            faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
           }
         }
       }
     }
+
     // check similarity of elements of the sides
     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
+      if ( nReplaceMap.size() == 2 ) // faces on input nodes not found
         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
-      else
+      }
+      else {
         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
+      }
       break; // do not return because it s necessary to remove tmp faces
     }
 
     // set nodes to merge
     // -------------------
 
-    if ( face[0] && face[1] )
-    {
+    if ( face[0] && face[1] )  {
       int nbNodes = face[0]->NbNodes();
       if ( nbNodes != face[1]->NbNodes() ) {
         MESSAGE("Diff nb of face nodes");
@@ -4983,9 +7029,12 @@ SMESH_MeshEditor::Sew_Error
         break; // do not return because it s necessary to remove tmp faces
       }
       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
-      if ( nbNodes == 3 )
+      if ( nbNodes == 3 ) {
+        //nReplaceMap.insert( TNodeNodeMap::value_type
+        //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
         nReplaceMap.insert( TNodeNodeMap::value_type
-                           ( notLinkNodes[0][0], notLinkNodes[1][0] ));
+                           ( notLinkNodes1[0], notLinkNodes2[0] ));
+      }
       else {
         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
           // analyse link orientation in faces
@@ -4999,36 +7048,46 @@ SMESH_MeshEditor::Sew_Error
             reverse[ iSide ] = !reverse[ iSide ];
         }
         if ( reverse[0] == reverse[1] ) {
-          nReplaceMap.insert( TNodeNodeMap::value_type
-                             ( notLinkNodes[0][0], notLinkNodes[1][0] ));
-          nReplaceMap.insert( TNodeNodeMap::value_type
-                             ( notLinkNodes[0][1], notLinkNodes[1][1] ));
+          //nReplaceMap.insert( TNodeNodeMap::value_type
+          //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
+          //nReplaceMap.insert( TNodeNodeMap::value_type
+          //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
+          for(int nn=0; nn<nbNodes-2; nn++) {
+            nReplaceMap.insert( TNodeNodeMap::value_type
+                             ( notLinkNodes1[nn], notLinkNodes2[nn] ));
+          }
         }
         else {
-          nReplaceMap.insert( TNodeNodeMap::value_type
-                             ( notLinkNodes[0][0], notLinkNodes[1][1] ));
-          nReplaceMap.insert( TNodeNodeMap::value_type
-                             ( notLinkNodes[0][1], notLinkNodes[1][0] ));
+          //nReplaceMap.insert( TNodeNodeMap::value_type
+          //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
+          //nReplaceMap.insert( TNodeNodeMap::value_type
+          //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
+          for(int nn=0; nn<nbNodes-2; nn++) {
+            nReplaceMap.insert( TNodeNodeMap::value_type
+                             ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
+          }
         }
       }
 
       // add other links of the faces to linkList
       // -----------------------------------------
 
-      const SMDS_MeshNode** nodes = faceNodes[ 0 ];
-      for ( iNode = 0; iNode < nbNodes; iNode++ )
-      {
-        linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
+      //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
+      for ( iNode = 0; iNode < nbNodes; iNode++ )  {
+        //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
+        linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
         if ( !iter_isnew.second ) { // already in a set: no need to process
           linkIdSet.erase( iter_isnew.first );
         }
         else // new in set == encountered for the first time: add
         {
-          const SMDS_MeshNode* n1 = nodes[ iNode ];
-          const SMDS_MeshNode* n2 = nodes[ iNode + 1];
-          linkList[0].push_back ( TPairOfNodes( n1, n2 ));
-          linkList[1].push_back ( TPairOfNodes( nReplaceMap[n1], nReplaceMap[n2] ));
+          //const SMDS_MeshNode* n1 = nodes[ iNode ];
+          //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
+          const SMDS_MeshNode* n1 = fnodes1[ iNode ];
+          const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
+          linkList[0].push_back ( NLink( n1, n2 ));
+          linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
         }
       }
     } // 2 faces found
@@ -5058,8 +7117,7 @@ SMESH_MeshEditor::Sew_Error
   // loop on nodes replacement map
   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
-    if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second )
-    {
+    if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
       nodeIDsToRemove.push_back( nToRemove->GetID() );
       // loop on elements sharing nToRemove
@@ -5068,7 +7126,7 @@ SMESH_MeshEditor::Sew_Error
         const SMDS_MeshElement* e = invElemIt->next();
         // get a new suite of nodes: make replacement
         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
-        const SMDS_MeshNode* nodes[ 8 ];
+        vector< const SMDS_MeshNode*> nodes( nbNodes );
         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
         while ( nIt->more() ) {
           const SMDS_MeshNode* n =
@@ -5084,11 +7142,183 @@ SMESH_MeshEditor::Sew_Error
         //         elemIDsToRemove.push_back( e->GetID() );
         //       else
         if ( nbReplaced )
-          aMesh->ChangeElementNodes( e, nodes, nbNodes );
+          aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
       }
-  }
+    }
 
   Remove( nodeIDsToRemove, true );
 
   return aResult;
 }
+
+//================================================================================
+  /*!
+   * \brief Find corresponding nodes in two sets of faces
+    * \param theSide1 - first face set
+    * \param theSide2 - second first face
+    * \param theFirstNode1 - a boundary node of set 1
+    * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
+    * \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
+   */
+//================================================================================
+
+//#define DEBUG_MATCHING_NODES
+
+SMESH_MeshEditor::Sew_Error
+SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
+                                    set<const SMDS_MeshElement*>& theSide2,
+                                    const SMDS_MeshNode*          theFirstNode1,
+                                    const SMDS_MeshNode*          theFirstNode2,
+                                    const SMDS_MeshNode*          theSecondNode1,
+                                    const SMDS_MeshNode*          theSecondNode2,
+                                    TNodeNodeMap &                nReplaceMap)
+{
+  set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
+
+  nReplaceMap.clear();
+  if ( theFirstNode1 != theFirstNode2 )
+    nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
+  if ( theSecondNode1 != theSecondNode2 )
+    nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
+
+  set< TLink > linkSet; // set of nodes where order of nodes is ignored
+  linkSet.insert( TLink( theFirstNode1, theSecondNode1 ));
+
+  list< NLink > linkList[2];
+  linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
+  linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
+
+  // loop on links in linkList; find faces by links and append links
+  // of the found faces to linkList
+  list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
+  for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
+    NLink link[] = { *linkIt[0], *linkIt[1] };
+    if ( linkSet.find( link[0] ) == linkSet.end() )
+      continue;
+
+    // by links, find faces in the face sets,
+    // and find indices of link nodes in the found faces;
+    // in a face set, there is only one or no face sharing a link
+    // ---------------------------------------------------------------
+
+    const SMDS_MeshElement* face[] = { 0, 0 };
+    list<const SMDS_MeshNode*> notLinkNodes[2];
+    //bool reverse[] = { false, false }; // order of notLinkNodes
+    int nbNodes[2];
+    for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
+    {
+      const SMDS_MeshNode* n1 = link[iSide].first;
+      const SMDS_MeshNode* n2 = link[iSide].second;
+      set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
+      set< const SMDS_MeshElement* > facesOfNode1;
+      for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
+      {
+        // during a loop of the first node, we find all faces around n1,
+        // during a loop of the second node, we find one face sharing both n1 and n2
+        const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
+        SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
+        while ( fIt->more() ) { // loop on faces sharing a node
+          const SMDS_MeshElement* f = fIt->next();
+          if (faceSet->find( f ) != faceSet->end() && // f is in face set
+              ! facesOfNode1.insert( f ).second ) // f encounters twice
+          {
+            if ( face[ iSide ] ) {
+              MESSAGE( "2 faces per link " );
+              return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
+            }
+            face[ iSide ] = f;
+            faceSet->erase( f );
+
+            // get not link nodes
+            int nbN = f->NbNodes();
+            if ( f->IsQuadratic() )
+              nbN /= 2;
+            nbNodes[ iSide ] = nbN;
+            list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
+            int i1 = f->GetNodeIndex( n1 );
+            int i2 = f->GetNodeIndex( n2 );
+            int iEnd = nbN, iBeg = -1, iDelta = 1;
+            bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
+            if ( reverse ) {
+              std::swap( iEnd, iBeg ); iDelta = -1;
+            }
+            int i = i2;
+            while ( true ) {
+              i += iDelta;
+              if ( i == iEnd ) i = iBeg + iDelta;
+              if ( i == i1 ) break;
+              nodes.push_back ( f->GetNode( i ) );
+            }
+          }
+        }
+      }
+    }
+    // check similarity of elements of the sides
+    if (( 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
+        return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
+      }
+      else {
+        return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
+      }
+    }
+
+    // set nodes to merge
+    // -------------------
+
+    if ( face[0] && face[1] )  {
+      if ( nbNodes[0] != nbNodes[1] ) {
+        MESSAGE("Diff nb of face nodes");
+        return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
+      }
+#ifdef DEBUG_MATCHING_NODES
+      cout << " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
+           << " F 1: " << face[0];
+      cout << "| Link 2: " << link[1].first->GetID() <<" "<< link[1].second->GetID()
+           << " F 2: " << face[1] << " | Bind: "<<endl ;
+#endif
+      int nbN = nbNodes[0];
+      {
+        list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
+        list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
+        for ( int i = 0 ; i < nbN - 2; ++i ) {
+#ifdef DEBUG_MATCHING_NODES
+          cout << (*n1)->GetID() << " to " << (*n2)->GetID() << endl;
+#endif
+          nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
+        }
+      }
+
+      // add other links of the face 1 to linkList
+      // -----------------------------------------
+
+      const SMDS_MeshElement* f0 = face[0];
+      const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
+      for ( int i = 0; i < nbN; i++ )
+      {
+        const SMDS_MeshNode* n2 = f0->GetNode( i );
+        pair< set< TLink >::iterator, bool > iter_isnew =
+          linkSet.insert( TLink( n1, n2 ));
+        if ( !iter_isnew.second ) { // already in a set: no need to process
+          linkSet.erase( iter_isnew.first );
+        }
+        else // new in set == encountered for the first time: add
+        {
+#ifdef DEBUG_MATCHING_NODES
+          cout << "Add link 1: " << n1->GetID() << " " << n2->GetID() << " ";
+          cout << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " << endl;
+#endif
+          linkList[0].push_back ( NLink( n1, n2 ));
+          linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
+        }
+        n1 = n2;
+      }
+    } // 2 faces found
+  } // loop on link lists
+
+  return SEW_OK;
+}