Salome HOME
Merge from V5_1_4_BR 07/05/2010
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
index 89354777b3e7e56da1292df7cef902e61a5d68f6..433c5116ef27964c1471e0ec7614ff06794b44c6 100644 (file)
@@ -1,4 +1,4 @@
-//  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
+//  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -19,6 +19,7 @@
 //
 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
+
 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
 // File      : SMESH_MeshEditor.cxx
 // Created   : Mon Apr 12 16:10:22 2004
 #include "SMESHDS_Group.hxx"
 #include "SMESHDS_Mesh.hxx"
 
-#include "SMESH_subMesh.hxx"
+#include "SMESH_Algo.hxx"
 #include "SMESH_ControlsDef.hxx"
+#include "SMESH_Group.hxx"
 #include "SMESH_MesherHelper.hxx"
 #include "SMESH_OctreeNode.hxx"
-#include "SMESH_Group.hxx"
+#include "SMESH_subMesh.hxx"
 
 #include "utilities.h"
 
-#include <BRep_Tool.hxx>
+#include <BRepAdaptor_Surface.hxx>
 #include <BRepClass3d_SolidClassifier.hxx>
+#include <BRep_Tool.hxx>
 #include <ElCLib.hxx>
 #include <Extrema_GenExtPS.hxx>
+#include <Extrema_POnCurv.hxx>
 #include <Extrema_POnSurf.hxx>
+#include <GC_MakeSegment.hxx>
 #include <Geom2d_Curve.hxx>
+#include <GeomAPI_ExtremaCurveCurve.hxx>
 #include <GeomAdaptor_Surface.hxx>
 #include <Geom_Curve.hxx>
+#include <Geom_Line.hxx>
 #include <Geom_Surface.hxx>
+#include <IntAna_IntConicQuad.hxx>
+#include <IntAna_Quadric.hxx>
 #include <Precision.hxx>
 #include <TColStd_ListOfInteger.hxx>
 #include <TopAbs_State.hxx>
 #include <gp_Vec.hxx>
 #include <gp_XY.hxx>
 #include <gp_XYZ.hxx>
+
 #include <math.h>
 
 #include <map>
 #include <set>
+#include <numeric>
+#include <limits>
 
 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
 
@@ -86,13 +98,6 @@ using namespace SMESH::Controls;
 
 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
-//typedef map<const SMDS_MeshNode*, vector<const SMDS_MeshNode*> >     TNodeOfNodeVecMap;
-//typedef TNodeOfNodeVecMap::iterator                                  TNodeOfNodeVecMapItr;
-//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() ) {}
-};
 
 //=======================================================================
 //function : SMESH_MeshEditor
@@ -120,6 +125,11 @@ SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
   int nbnode = node.size();
   SMESHDS_Mesh* mesh = GetMeshDS();
   switch ( type ) {
+  case SMDSAbs_0DElement:
+    if ( nbnode == 1 )
+      if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
+      else      e = mesh->Add0DElement      (node[0] );
+    break;
   case SMDSAbs_Edge:
     if ( nbnode == 2 )
       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
@@ -269,17 +279,17 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
             smmap.insert( sm );
     }
     // Find sub-meshes to notify about modification
-//     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
-//     while ( nodeIt->more() ) {
-//       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
-//       const SMDS_PositionPtr& aPosition = node->GetPosition();
-//       if ( aPosition.get() ) {
-//         if ( int aShapeID = aPosition->GetShapeId() ) {
-//           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
-//             smmap.insert( sm );
-//         }
-//       }
-//     }
+    //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
+    //     while ( nodeIt->more() ) {
+    //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
+    //       const SMDS_PositionPtr& aPosition = node->GetPosition();
+    //       if ( aPosition.get() ) {
+    //         if ( int aShapeID = aPosition->GetShapeId() ) {
+    //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
+    //             smmap.insert( sm );
+    //         }
+    //       }
+    //     }
 
     // Do remove
     if ( isNodes )
@@ -295,9 +305,9 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
       (*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 );
+  //   // Check if the whole mesh becomes empty
+  //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
+  //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
 
   return true;
 }
@@ -1106,6 +1116,7 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
 //function : BestSplit
 //purpose  : Find better diagonal for cutting.
 //=======================================================================
+
 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
                                  SMESH::Controls::NumericalFunctorPtr theCrit)
 {
@@ -1147,6 +1158,453 @@ int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
   return -1;
 }
 
+namespace
+{
+  // Methods of splitting volumes into tetra
+
+  const int theHexTo5_1[5*4+1] =
+    {
+      0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
+    };
+  const int theHexTo5_2[5*4+1] =
+    {
+      1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
+    };
+  const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
+
+  const int theHexTo6_1[6*4+1] =
+    {
+      1, 5, 6, 0,    0, 1, 2, 6,     0, 4, 5, 6,    0, 4, 6, 7,     0, 2, 3, 6,   0, 3, 7, 6,  -1
+    };
+  const int theHexTo6_2[6*4+1] =
+    {
+      2, 6, 7, 1,    1, 2, 3, 7,     1, 5, 6, 7,    1, 5, 7, 4,     1, 3, 0, 7,   1, 0, 4, 7,  -1
+    };
+  const int theHexTo6_3[6*4+1] =
+    {
+      3, 7, 4, 2,    2, 3, 0, 4,     2, 6, 7, 4,    2, 6, 4, 5,     2, 0, 1, 4,   2, 1, 5, 4,  -1
+    };
+  const int theHexTo6_4[6*4+1] =
+    {
+      0, 4, 5, 3,    3, 0, 1, 5,     3, 7, 4, 5,    3, 7, 5, 6,     3, 1, 2, 5,   3, 2, 6, 5,  -1
+    };
+  const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
+
+  const int thePyraTo2_1[2*4+1] =
+    {
+      0, 1, 2, 4,    0, 2, 3, 4,   -1
+    };
+  const int thePyraTo2_2[2*4+1] =
+    {
+      1, 2, 3, 4,    1, 3, 0, 4,   -1
+    };
+  const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
+
+  const int thePentaTo3_1[3*4+1] =
+    {
+      0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
+    };
+  const int thePentaTo3_2[3*4+1] =
+    {
+      1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
+    };
+  const int thePentaTo3_3[3*4+1] =
+    {
+      2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
+    };
+  const int thePentaTo3_4[3*4+1] =
+    {
+      0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
+    };
+  const int thePentaTo3_5[3*4+1] =
+    {
+      1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
+    };
+  const int thePentaTo3_6[3*4+1] =
+    {
+      2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
+    };
+  const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
+                                thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
+
+  struct TTriangleFacet //!< stores indices of three nodes of tetra facet
+  {
+    int _n1, _n2, _n3;
+    TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
+    bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
+    bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
+  };
+  struct TSplitMethod
+  {
+    int        _nbTetra;
+    const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
+    bool       _baryNode;     //!< additional node is to be created at cell barycenter
+    bool       _ownConn;      //!< to delete _connectivity in destructor
+
+    TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
+      : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
+    ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
+    bool hasFacet( const TTriangleFacet& facet ) const
+    {
+      const int* tetConn = _connectivity;
+      for ( ; tetConn[0] >= 0; tetConn += 4 )
+        if (( facet.contains( tetConn[0] ) +
+              facet.contains( tetConn[1] ) +
+              facet.contains( tetConn[2] ) +
+              facet.contains( tetConn[3] )) == 3 )
+          return true;
+      return false;
+    }
+  };
+
+  //=======================================================================
+  /*!
+   * \brief return TSplitMethod for the given element
+   */
+  //=======================================================================
+
+  TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
+  {
+    int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
+
+    // Find out how adjacent volumes are split
+
+    vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
+    int hasAdjacentSplits = 0, maxTetConnSize = 0;
+    for ( int iF = 0; iF < vol.NbFaces(); ++iF )
+    {
+      int nbNodes = vol.NbFaceNodes( iF ) / iQ;
+      maxTetConnSize += 4 * ( nbNodes - 2 );
+      if ( nbNodes < 4 ) continue;
+
+      list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
+      const int* nInd = vol.GetFaceNodesIndices( iF );
+      if ( nbNodes == 4 )
+      {
+        TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
+        TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
+        if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
+        else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
+      }
+      else
+      {
+        int iCom = 0; // common node of triangle faces to split into
+        for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
+        {
+          TTriangleFacet t012( nInd[ iQ * ( iCom             )],
+                               nInd[ iQ * ( (iCom+1)%nbNodes )],
+                               nInd[ iQ * ( (iCom+2)%nbNodes )]);
+          TTriangleFacet t023( nInd[ iQ * ( iCom             )],
+                               nInd[ iQ * ( (iCom+2)%nbNodes )],
+                               nInd[ iQ * ( (iCom+3)%nbNodes )]);
+          if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
+          {
+            triaSplits.push_back( t012 );
+            triaSplits.push_back( t023 );
+            break;
+          }
+        }
+      }
+      if ( !triaSplits.empty() )
+        hasAdjacentSplits = true;
+    }
+
+    // Among variants of split method select one compliant with adjacent volumes
+
+    TSplitMethod method;
+    if ( !vol.Element()->IsPoly() )
+    {
+      int nbVariants = 2, nbTet = 0;
+      const int** connVariants = 0;
+      switch ( vol.Element()->GetEntityType() )
+      {
+      case SMDSEntity_Hexa:
+      case SMDSEntity_Quad_Hexa:
+        if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 )
+          connVariants = theHexTo5, nbTet = 5;
+        else
+          connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
+        break;
+      case SMDSEntity_Pyramid:
+      case SMDSEntity_Quad_Pyramid:
+        connVariants = thePyraTo2;  nbTet = 2;
+        break;
+      case SMDSEntity_Penta:
+      case SMDSEntity_Quad_Penta:
+        connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
+        break;
+      default:
+        nbVariants = 0;
+      }
+      for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
+      {
+        // check method compliancy with adjacent tetras,
+        // all found splits must be among facets of tetras described by this method
+        method = TSplitMethod( nbTet, connVariants[variant] );
+        if ( hasAdjacentSplits && method._nbTetra > 0 )
+        {
+          bool facetCreated = true;
+          for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
+          {
+            list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
+            for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
+              facetCreated = method.hasFacet( *facet );
+          }
+          if ( !facetCreated )
+            method = TSplitMethod(0); // incompatible method
+        }
+      }
+    }
+    if ( method._nbTetra < 1 )
+    {
+      // No standard method is applicable, use a generic solution:
+      // each facet of a volume is split into triangles and
+      // each of triangles and a volume barycenter form a tetrahedron.
+
+      int* connectivity = new int[ maxTetConnSize + 1 ];
+      method._connectivity = connectivity;
+      method._ownConn = true;
+      method._baryNode = true;
+
+      int connSize = 0;
+      int baryCenInd = vol.NbNodes();
+      for ( int iF = 0; iF < vol.NbFaces(); ++iF )
+      {
+        const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
+        const int*   nInd = vol.GetFaceNodesIndices( iF );
+        // find common node of triangle facets of tetra to create
+        int iCommon = 0; // index in linear numeration
+        const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
+        if ( !triaSplits.empty() )
+        {
+          // by found facets
+          const TTriangleFacet* facet = &triaSplits.front();
+          for ( ; iCommon < nbNodes-1 ; ++iCommon )
+            if ( facet->contains( nInd[ iQ * iCommon ]) &&
+                 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
+              break;
+        }
+        else if ( nbNodes > 3 )
+        {
+          // find the best method of splitting into triangles by aspect ratio
+          SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
+          map< double, int > badness2iCommon;
+          const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
+          int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
+          for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
+            for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
+            {
+              SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
+                                      nodes[ iQ*((iLast-1)%nbNodes)],
+                                      nodes[ iQ*((iLast  )%nbNodes)]);
+              double badness = getBadRate( &tria, aspectRatio );
+              badness2iCommon.insert( make_pair( badness, iCommon ));
+            }
+          // use iCommon with lowest badness
+          iCommon = badness2iCommon.begin()->second;
+        }
+        if ( iCommon >= nbNodes )
+          iCommon = 0; // something wrong
+        // fill connectivity of tetra
+        int nbTet = nbNodes - 2;
+        for ( int i = 0; i < nbTet; ++i )
+        {
+          int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
+          if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
+          connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
+          connectivity[ connSize++ ] = nInd[ iQ * i1 ];
+          connectivity[ connSize++ ] = nInd[ iQ * i2 ];
+          connectivity[ connSize++ ] = baryCenInd;
+          ++method._nbTetra;
+        }
+      }
+      connectivity[ connSize++ ] = -1;
+    }
+    return method;
+  }
+  //================================================================================
+  /*!
+   * \brief Check if there is a tetraherdon adjacent to the given element via this facet
+   */
+  //================================================================================
+
+  bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
+  {
+    // find the tetrahedron including the three nodes of facet
+    const SMDS_MeshNode* n1 = elem->GetNode(_n1);
+    const SMDS_MeshNode* n2 = elem->GetNode(_n2);
+    const SMDS_MeshNode* n3 = elem->GetNode(_n3);
+    SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
+    while ( volIt1->more() )
+    {
+      const SMDS_MeshElement* v = volIt1->next();
+      if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
+        continue;
+      SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
+      while ( volIt2->more() )
+        if ( v != volIt2->next() )
+          continue;
+      SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
+      while ( volIt3->more() )
+        if ( v == volIt3->next() )
+          return true;
+    }
+    return false;
+  }
+} // namespace
+
+//=======================================================================
+//function : SplitVolumesIntoTetra
+//purpose  : Split volumic elements into tetrahedra.
+//=======================================================================
+
+void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
+                                              const int                theMethodFlags)
+{
+  // std-like iterator on coordinates of nodes of mesh element
+  typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
+  NXyzIterator xyzEnd;
+
+  SMDS_VolumeTool    volTool;
+  SMESH_MesherHelper helper( *GetMesh());
+
+  SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
+  SMESHDS_SubMesh* fSubMesh = subMesh;
+  
+  SMESH_SequenceOfElemPtr newNodes, newElems;
+
+  TIDSortedElemSet::const_iterator elem = theElems.begin();
+  for ( ; elem != theElems.end(); ++elem )
+  {
+    SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
+    if ( geomType <= SMDSEntity_Quad_Tetra )
+      continue; // tetra or face or ...
+
+    if ( !volTool.Set( *elem )) continue; // not volume? strange...
+
+    TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
+    if ( splitMethod._nbTetra < 1 ) continue;
+
+    // find submesh to add new tetras in
+    if ( !subMesh || !subMesh->Contains( *elem ))
+    {
+      int shapeID = FindShape( *elem );
+      helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
+      subMesh = GetMeshDS()->MeshElements( shapeID );
+    }
+    int iQ;
+    if ( (*elem)->IsQuadratic() )
+    {
+      iQ = 2;
+      // add quadratic links to the helper
+      for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
+      {
+        const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
+        for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
+          helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
+      }
+      helper.SetIsQuadratic( true );
+    }
+    else
+    {
+      iQ = 1;
+      helper.SetIsQuadratic( false );
+    }
+    vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
+    if ( splitMethod._baryNode )
+    {
+      // make a node at barycenter
+      gp_XYZ gc( 0,0,0 );
+      gc = accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd, gc ) / nodes.size();
+      SMDS_MeshNode* gcNode = helper.AddNode( gc.X(), gc.Y(), gc.Z() );
+      nodes.push_back( gcNode );
+      newNodes.Append( gcNode );
+    }
+
+    // make tetras
+    helper.SetElementsOnShape( true );
+    vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
+    const int* tetConn = splitMethod._connectivity;
+    for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
+      newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
+                                                       nodes[ tetConn[1] ],
+                                                       nodes[ tetConn[2] ],
+                                                       nodes[ tetConn[3] ]));
+
+    ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
+
+    // Split faces on sides of the split volume
+
+    const SMDS_MeshNode** volNodes = volTool.GetNodes();
+    for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
+    {
+      const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
+      if ( nbNodes < 4 ) continue;
+
+      // find an existing face
+      vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
+                                           volTool.GetFaceNodes( iF ) + nbNodes*iQ );
+      while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
+      {
+        // among possible triangles create ones discribed by split method
+        const int* nInd = volTool.GetFaceNodesIndices( iF );
+        int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
+        int iCom = 0; // common node of triangle faces to split into
+        list< TTriangleFacet > facets;
+        for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
+        {
+          TTriangleFacet t012( nInd[ iQ * ( iCom                )],
+                               nInd[ iQ * ( (iCom+1)%nbNodes )],
+                               nInd[ iQ * ( (iCom+2)%nbNodes )]);
+          TTriangleFacet t023( nInd[ iQ * ( iCom                )],
+                               nInd[ iQ * ( (iCom+2)%nbNodes )],
+                               nInd[ iQ * ( (iCom+3)%nbNodes )]);
+          if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
+          {
+            facets.push_back( t012 );
+            facets.push_back( t023 );
+            for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
+              facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
+                                                nInd[ iQ * ((iLast-1)%nbNodes )],
+                                                nInd[ iQ * ((iLast  )%nbNodes )]));
+            break;
+          }
+        }
+        // find submesh to add new faces in
+        if ( !fSubMesh || !fSubMesh->Contains( face ))
+        {
+          int shapeID = FindShape( face );
+          fSubMesh = GetMeshDS()->MeshElements( shapeID );
+        }
+        // make triangles
+        helper.SetElementsOnShape( false );
+        vector< const SMDS_MeshElement* > triangles;
+        list< TTriangleFacet >::iterator facet = facets.begin();
+        for ( ; facet != facets.end(); ++facet )
+        {
+          if ( !volTool.IsFaceExternal( iF ))
+            swap( facet->_n2, facet->_n3 );
+          triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
+                                               volNodes[ facet->_n2 ],
+                                               volNodes[ facet->_n3 ]));
+          if ( triangles.back() && fSubMesh )
+            fSubMesh->AddElement( triangles.back());
+          newElems.Append( triangles.back() );
+        }
+        ReplaceElemInGroups( face, triangles, GetMeshDS() );
+        GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
+      }
+
+    } // loop on volume faces to split them into triangles
+
+    GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
+
+  } // loop on volumes to split
+
+  myLastCreatedNodes = newNodes;
+  myLastCreatedElems = newElems;
+}
+
 //=======================================================================
 //function : AddToSameGroups
 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
@@ -1188,10 +1646,11 @@ void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
   }
 }
 
-//=======================================================================
-//function : ReplaceElemInGroups
-//purpose  : replace elemToRm by elemToAdd in the all groups
-//=======================================================================
+//================================================================================
+/*!
+ * \brief Replace elemToRm by elemToAdd in the all groups
+ */
+//================================================================================
 
 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
                                             const SMDS_MeshElement* elemToAdd,
@@ -1208,6 +1667,29 @@ void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
   }
 }
 
+//================================================================================
+/*!
+ * \brief Replace elemToRm by elemToAdd in the all groups
+ */
+//================================================================================
+
+void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
+                                            const vector<const SMDS_MeshElement*>& elemToAdd,
+                                            SMESHDS_Mesh *                         aMesh)
+{
+  const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
+  if (!groups.empty())
+  {
+    set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
+    for ( ; grIt != groups.end(); grIt++ ) {
+      SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
+      if ( group && group->SMDSGroup().Remove( elemToRm ) )
+        for ( int i = 0; i < elemToAdd.size(); ++i )
+          group->SMDSGroup().Add( elemToAdd[ i ] );
+    }
+  }
+}
+
 //=======================================================================
 //function : QuadToTri
 //purpose  : Cut quadrangles into triangles.
@@ -1411,7 +1893,7 @@ double getAngle(const SMDS_MeshElement * tr1,
 // and able to return nodes by that ID
 // =================================================
 class LinkID_Gen {
- public:
+public:
 
   LinkID_Gen( const SMESHDS_Mesh* theMesh )
     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
@@ -1434,7 +1916,7 @@ class LinkID_Gen {
     return true;
   }
 
- private:
+private:
   LinkID_Gen();
   const SMESHDS_Mesh* myMesh;
   long                myMaxID;
@@ -1743,15 +2225,15 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
 //=============================================================================
 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
 {
-  if ( i1 == i2 )
-    return;
-  int tmp = idNodes[ i1 ];
-  idNodes[ i1 ] = idNodes[ i2 ];
-  idNodes[ i2 ] = tmp;
-  gp_Pnt Ptmp = P[ i1 ];
-  P[ i1 ] = P[ i2 ];
-  P[ i2 ] = Ptmp;
-  DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
+if ( i1 == i2 )
+return;
+int tmp = idNodes[ i1 ];
+idNodes[ i1 ] = idNodes[ i2 ];
+idNodes[ i2 ] = tmp;
+gp_Pnt Ptmp = P[ i1 ];
+P[ i1 ] = P[ i2 ];
+P[ i2 ] = Ptmp;
+DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
 }
 
 //=======================================================================
@@ -1762,7 +2244,7 @@ static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
 //=======================================================================
 
 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
-                                     int               idNodes[] )
+int               idNodes[] )
 {
   gp_Pnt P[4];
   int i;
@@ -1791,10 +2273,10 @@ int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
       i = 1;
     swap ( i, i + 1, idNodes, P );
 
-//     for ( int ii = 0; ii < 4; ii++ ) {
-//       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
-//       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
-//     }
+    //     for ( int ii = 0; ii < 4; ii++ ) {
+    //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
+    //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
+    //     }
   }
   return i;
 }
@@ -1910,7 +2392,7 @@ bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
           faceNodes.insert( idNodes[ 2 ] );
           faceNodes.insert( idNodes[ iMin ] );
           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
-            << " leastDist = " << leastDist);
+                  << " leastDist = " << leastDist);
           if ( leastDist <= DBL_MIN )
             break;
         }
@@ -1948,11 +2430,11 @@ bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
     P[ i ] = P[ i+1 ];
     P[ i+1 ] = Ptmp;
   }
-//   else
-//     for ( int ii = 0; ii < 4; ii++ ) {
-//       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
-//       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
-//    }
+  //   else
+  //     for ( int ii = 0; ii < 4; ii++ ) {
+  //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
+  //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
+  //    }
 
   // Gravity center of the top and bottom faces
   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
@@ -2004,11 +2486,11 @@ bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
     swap( 5, 7, idNodes, P );
   }
 
-//   DUMPSO( "OUTPUT: ========================================");
-//   for ( i = 0; i < 8; i++ ) {
-//     float *p = ugrid->GetPoint(idNodes[i]);
-//     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
-//   }
+  //   DUMPSO( "OUTPUT: ========================================");
+  //   for ( i = 0; i < 8; i++ ) {
+  //     float *p = ugrid->GetPoint(idNodes[i]);
+  //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
+  //   }
 
   return true;
 }*/
@@ -2016,11 +2498,11 @@ bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
 //================================================================================
 /*!
  * \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
+ * \param theNode - the node
+ * \param linkedNodes - the found nodes
+ * \param type - the type of elements to check
+ *
+ * Medium nodes are ignored
  */
 //================================================================================
 
@@ -2300,14 +2782,14 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
     }
     int nbElemOnFace = 0;
     itElem = theElems.begin();
-     // loop on not yet smoothed elements: look for elems on a face
+    // loop on not yet smoothed elements: look for elems on a face
     while ( itElem != theElems.end() ) {
       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
         break; // all elements found
 
       const SMDS_MeshElement* elem = *itElem;
       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
-          ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
+           ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
         ++itElem;
         continue;
       }
@@ -2366,19 +2848,19 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
         if ( uvMap.find( node ) == uvMap.end() )
           uvCheckNodes.push_back( node );
         // add nodes of elems sharing node
-//         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
-//         while ( eIt->more() ) {
-//           const SMDS_MeshElement* e = eIt->next();
-//           if ( e != elem ) {
-//             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
-//             while ( nIt->more() ) {
-//               const SMDS_MeshNode* n =
-//                 static_cast<const SMDS_MeshNode*>( nIt->next() );
-//               if ( uvMap.find( n ) == uvMap.end() )
-//                 uvCheckNodes.push_back( n );
-//             }
-//           }
-//         }
+        //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
+        //         while ( eIt->more() ) {
+        //           const SMDS_MeshElement* e = eIt->next();
+        //           if ( e != elem ) {
+        //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
+        //             while ( nIt->more() ) {
+        //               const SMDS_MeshNode* n =
+        //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
+        //               if ( uvMap.find( n ) == uvMap.end() )
+        //                 uvCheckNodes.push_back( n );
+        //             }
+        //           }
+        //         }
       }
       // check UV on face
       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
@@ -2788,33 +3270,33 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
       return;
     }
 
-    issimple[iNode] = (listNewNodes.size()==nbSteps);
+    issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
 
     itNN[ iNode ] = listNewNodes.begin();
     prevNod[ iNode ] = node;
     nextNod[ iNode ] = listNewNodes.front();
-    if( !issimple[iNode] ) {
+    if( !elem->IsQuadratic() || !issimple[iNode] ) {
       if ( prevNod[ iNode ] != nextNod [ iNode ])
-       iNotSameNode = iNode;
+        iNotSameNode = iNode;
       else {
-       iSameNode = iNode;
-       //nbSame++;
-       sames[nbSame++] = iNode;
+        iSameNode = iNode;
+        //nbSame++;
+        sames[nbSame++] = iNode;
       }
     }
   }
 
   //cout<<"  nbSame = "<<nbSame<<endl;
   if ( nbSame == nbNodes || nbSame > 2) {
-    //MESSAGE( " Too many same nodes of element " << elem->GetID() );
-    INFOS( " Too many same nodes of element " << elem->GetID() );
+    MESSAGE( " Too many same nodes of element " << elem->GetID() );
+    //INFOS( " Too many same nodes of element " << elem->GetID() );
     return;
   }
 
-//  if( elem->IsQuadratic() && nbSame>0 ) {
-//    MESSAGE( "Can not rotate quadratic 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;
   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
@@ -2824,11 +3306,11 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
     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;
+  //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;
@@ -2919,7 +3401,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
           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]);
@@ -2931,7 +3413,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
           }
           else {
             return;
-         }
+          }
         }
         break;
       }
@@ -2966,140 +3448,140 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
       }
       case 6: { // quadratic triangle
         // create pentahedron with 15 nodes
-       if(nbSame==0) {
-         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]);
-         }
-       }
-       else if(nbSame==1) {
-         // 2d order pyramid of 13 nodes
-         //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
+        if(nbSame==0) {
+          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]);
+          }
+        }
+        else if(nbSame==1) {
+          // 2d order pyramid of 13 nodes
+          //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
           //                                 int n12,int n23,int n34,int n41,
           //                                 int n15,int n25,int n35,int n45, int ID);
-         int n5 = iSameNode;
-         int n1,n4,n41,n15,n45;
-         if(i0>0) { // reversed case
-           n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
-           n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
-           n41 = n1 + 3;
-           n15 = n5 + 3;
-           n45 = n4 + 3;
-         }
-         else {
-           n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
-           n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
-           n41 = n4 + 3;
-           n15 = n1 + 3;
-           n45 = n5 + 3;
-         }
-         aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
-                             nextNod[n4], prevNod[n4], prevNod[n5],
-                             midlNod[n1], nextNod[n41],
-                             midlNod[n4], prevNod[n41],
-                             prevNod[n15], nextNod[n15],
-                             nextNod[n45], prevNod[n45]);
-       }
-       else if(nbSame==2) {
-         // 2d order tetrahedron of 10 nodes
-         //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
-         //                                 int n12,int n23,int n31,
-         //                                 int n14,int n24,int n34, int ID);
-         int n1 = iNotSameNode;
-         int n2,n3,n12,n23,n31;
-         if(i0>0) { // reversed case
-           n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
-           n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
-           n12 = n2 + 3;
-           n23 = n3 + 3;
-           n31 = n1 + 3;
-         }
-         else {
-           n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
-           n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
-           n12 = n1 + 3;
-           n23 = n2 + 3;
-           n31 = n3 + 3;
-         }
-         aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
-                                      prevNod[n12], prevNod[n23], prevNod[n31],
-                                      midlNod[n1], nextNod[n12], nextNod[n31]);
-       }
+          int n5 = iSameNode;
+          int n1,n4,n41,n15,n45;
+          if(i0>0) { // reversed case
+            n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
+            n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
+            n41 = n1 + 3;
+            n15 = n5 + 3;
+            n45 = n4 + 3;
+          }
+          else {
+            n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
+            n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
+            n41 = n4 + 3;
+            n15 = n1 + 3;
+            n45 = n5 + 3;
+          }
+          aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
+                                      nextNod[n4], prevNod[n4], prevNod[n5],
+                                      midlNod[n1], nextNod[n41],
+                                      midlNod[n4], prevNod[n41],
+                                      prevNod[n15], nextNod[n15],
+                                      nextNod[n45], prevNod[n45]);
+        }
+        else if(nbSame==2) {
+          // 2d order tetrahedron of 10 nodes
+          //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
+          //                                 int n12,int n23,int n31,
+          //                                 int n14,int n24,int n34, int ID);
+          int n1 = iNotSameNode;
+          int n2,n3,n12,n23,n31;
+          if(i0>0) { // reversed case
+            n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
+            n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
+            n12 = n2 + 3;
+            n23 = n3 + 3;
+            n31 = n1 + 3;
+          }
+          else {
+            n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
+            n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
+            n12 = n1 + 3;
+            n23 = n2 + 3;
+            n31 = n3 + 3;
+          }
+          aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
+                                       prevNod[n12], prevNod[n23], prevNod[n31],
+                                       midlNod[n1], nextNod[n12], nextNod[n31]);
+        }
         break;
       }
       case 8: { // quadratic quadrangle
-       if(nbSame==0) {
-         // 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]);
-         }
-       }
-       else if(nbSame==1) { 
-         // --- pyramid + pentahedron - can not be created since it is needed 
-         // additional middle node ot the center of face
-         INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
-         return;
-       }
-       else if(nbSame==2) {
-         // 2d order Pentahedron with 15 nodes
-         //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
+        if(nbSame==0) {
+          // 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]);
+          }
+        }
+        else if(nbSame==1) { 
+          // --- pyramid + pentahedron - can not be created since it is needed 
+          // additional middle node ot the center of face
+          INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
+          return;
+        }
+        else if(nbSame==2) {
+          // 2d order Pentahedron with 15 nodes
+          //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
           //                                 int n14,int n25,int n36, int ID);
-         int n1,n2,n4,n5;
+          int n1,n2,n4,n5;
           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
             // iBeforeSame is same too
-           n1 = iBeforeSame;
-           n2 = iOpposSame;
-           n4 = iSameNode;
-           n5 = iAfterSame;
-         }
-         else {
+            n1 = iBeforeSame;
+            n2 = iOpposSame;
+            n4 = iSameNode;
+            n5 = iAfterSame;
+          }
+          else {
             // iAfterSame is same too
-           n1 = iSameNode;
-           n2 = iBeforeSame;
-           n4 = iAfterSame;
-           n5 = iOpposSame;
-         }
-         int n12,n45,n14,n25;
-         if(i0>0) { //reversed case
-           n12 = n1 + 4;
-           n45 = n5 + 4;
-           n14 = n4 + 4;
-           n25 = n2 + 4;
-         }
-         else {
-           n12 = n2 + 4;
-           n45 = n4 + 4;
-           n14 = n1 + 4;
-           n25 = n5 + 4;
-         }
-         aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
-                                      prevNod[n4], prevNod[n5], nextNod[n5],
-                                      prevNod[n12], midlNod[n2], nextNod[n12],
-                                      prevNod[n45], midlNod[n5], nextNod[n45],
-                                      prevNod[n14], prevNod[n25], nextNod[n25]);
-       }
+            n1 = iSameNode;
+            n2 = iBeforeSame;
+            n4 = iAfterSame;
+            n5 = iOpposSame;
+          }
+          int n12,n45,n14,n25;
+          if(i0>0) { //reversed case
+            n12 = n1 + 4;
+            n45 = n5 + 4;
+            n14 = n4 + 4;
+            n25 = n2 + 4;
+          }
+          else {
+            n12 = n2 + 4;
+            n45 = n4 + 4;
+            n14 = n1 + 4;
+            n25 = n5 + 4;
+          }
+          aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
+                                       prevNod[n4], prevNod[n5], nextNod[n5],
+                                       prevNod[n12], midlNod[n2], nextNod[n12],
+                                       prevNod[n45], midlNod[n5], nextNod[n45],
+                                       prevNod[n14], prevNod[n25], nextNod[n25]);
+        }
         break;
       }
       default: {
@@ -3408,17 +3890,17 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
                   if ( !f ) {
                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
                                                              nodes[1], nodes[3], nodes[5]));
-                 }
+                  }
                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
-                   const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
-                   tmpnodes[0] = nodes[0];
-                   tmpnodes[1] = nodes[2];
-                   tmpnodes[2] = nodes[4];
-                   tmpnodes[3] = nodes[1];
-                   tmpnodes[4] = nodes[3];
-                   tmpnodes[5] = nodes[5];
+                    const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
+                    tmpnodes[0] = nodes[0];
+                    tmpnodes[1] = nodes[2];
+                    tmpnodes[2] = nodes[4];
+                    tmpnodes[3] = nodes[1];
+                    tmpnodes[4] = nodes[3];
+                    tmpnodes[5] = nodes[5];
                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
-                 }
+                  }
                 }
                 else {       /////// quadratic quadrangle
                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
@@ -3426,19 +3908,19 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
                   if ( !f ) {
                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
-                 }
+                  }
                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
-                   const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
-                   tmpnodes[0] = nodes[0];
-                   tmpnodes[1] = nodes[2];
-                   tmpnodes[2] = nodes[4];
-                   tmpnodes[3] = nodes[6];
-                   tmpnodes[4] = nodes[1];
-                   tmpnodes[5] = nodes[3];
-                   tmpnodes[6] = nodes[5];
-                   tmpnodes[7] = nodes[7];
+                    const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
+                    tmpnodes[0] = nodes[0];
+                    tmpnodes[1] = nodes[2];
+                    tmpnodes[2] = nodes[4];
+                    tmpnodes[3] = nodes[6];
+                    tmpnodes[4] = nodes[1];
+                    tmpnodes[5] = nodes[3];
+                    tmpnodes[6] = nodes[5];
+                    tmpnodes[7] = nodes[7];
                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
-                 }
+                  }
                 }
               }
               else { //////// polygon
@@ -3598,51 +4080,51 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
             myLastCreatedNodes.Append(newNode);
             srcNodes.Append( node );
-           listNewNodes.push_back( newNode );
+            listNewNodes.push_back( newNode );
+          }
+          else {
+            listNewNodes.push_back( newNode );
+            if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+              listNewNodes.push_back( newNode );
+            }
           }
-         else {
-           listNewNodes.push_back( newNode );
-           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
-             listNewNodes.push_back( newNode );
-           }
-         }
         }
       }
       /*
-      else {
+        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;
-           if ( !isOnAxis ) {
-             for(int i = 0; i<theNbSteps; i++) {
-               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
-               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
-               cout<<"    3 AddNode:  "<<newNode;
-               myLastCreatedNodes.Append(newNode);
-               listNewNodes.push_back( newNode );
-               srcNodes.Append( node );
-               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
-               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
-               cout<<"    4 AddNode:  "<<newNode;
-               myLastCreatedNodes.Append(newNode);
-               srcNodes.Append( node );
-               listNewNodes.push_back( newNode );
-             }
-            }
-           else {
-             listNewNodes.push_back( newNode );
-           }
-          }
+        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;
+        if ( !isOnAxis ) {
+        for(int i = 0; i<theNbSteps; i++) {
+        aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+        newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+        cout<<"    3 AddNode:  "<<newNode;
+        myLastCreatedNodes.Append(newNode);
+        listNewNodes.push_back( newNode );
+        srcNodes.Append( node );
+        aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+        newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+        cout<<"    4 AddNode:  "<<newNode;
+        myLastCreatedNodes.Append(newNode);
+        srcNodes.Append( node );
+        listNewNodes.push_back( newNode );
+        }
+        }
+        else {
+        listNewNodes.push_back( newNode );
+        }
+        }
+        }
         }
-      }
       */
       newNodesItVec.push_back( nIt );
     }
@@ -3652,7 +4134,7 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
 
   if ( theMakeWalls )
     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
-  
+
   PGroupIDs newGroupIDs;
   if ( theMakeGroups )
     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
@@ -3891,59 +4373,59 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
 //=======================================================================
 class SMESH_MeshEditor_PathPoint {
 public:
-  SMESH_MeshEditor_PathPoint() {
-    myPnt.SetCoord(99., 99., 99.);
-    myTgt.SetCoord(1.,0.,0.);
-    myAngle=0.;
-    myPrm=0.;
-  }
-  void SetPnt(const gp_Pnt& aP3D){
-    myPnt=aP3D;
-  }
-  void SetTangent(const gp_Dir& aTgt){
-    myTgt=aTgt;
-  }
-  void SetAngle(const double& aBeta){
-    myAngle=aBeta;
-  }
-  void SetParameter(const double& aPrm){
-    myPrm=aPrm;
-  }
-  const gp_Pnt& Pnt()const{
-    return myPnt;
-  }
-  const gp_Dir& Tangent()const{
-    return myTgt;
-  }
-  double Angle()const{
-    return myAngle;
-  }
-  double Parameter()const{
-    return myPrm;
-  }
-
-protected:
-  gp_Pnt myPnt;
-  gp_Dir myTgt;
-  double myAngle;
-  double myPrm;
-};
-*/
-
-//=======================================================================
-//function : ExtrusionAlongTrack
+SMESH_MeshEditor_PathPoint() {
+myPnt.SetCoord(99., 99., 99.);
+myTgt.SetCoord(1.,0.,0.);
+myAngle=0.;
+myPrm=0.;
+}
+void SetPnt(const gp_Pnt& aP3D){
+myPnt=aP3D;
+}
+void SetTangent(const gp_Dir& aTgt){
+myTgt=aTgt;
+}
+void SetAngle(const double& aBeta){
+myAngle=aBeta;
+}
+void SetParameter(const double& aPrm){
+myPrm=aPrm;
+}
+const gp_Pnt& Pnt()const{
+return myPnt;
+}
+const gp_Dir& Tangent()const{
+return myTgt;
+}
+double Angle()const{
+return myAngle;
+}
+double Parameter()const{
+return myPrm;
+}
+
+protected:
+gp_Pnt myPnt;
+gp_Dir myTgt;
+double myAngle;
+double myPrm;
+};
+*/
+
+//=======================================================================
+//function : ExtrusionAlongTrack
 //purpose  :
 //=======================================================================
 SMESH_MeshEditor::Extrusion_Error
-  SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
-                                        SMESH_subMesh*       theTrack,
-                                        const SMDS_MeshNode* theN1,
-                                        const bool           theHasAngles,
-                                        list<double>&        theAngles,
-                                        const bool           theLinearVariation,
-                                        const bool           theHasRefPoint,
-                                        const gp_Pnt&        theRefPoint,
-                                         const bool           theMakeGroups)
+SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
+                                       SMESH_subMesh*       theTrack,
+                                       const SMDS_MeshNode* theN1,
+                                       const bool           theHasAngles,
+                                       list<double>&        theAngles,
+                                       const bool           theLinearVariation,
+                                       const bool           theHasRefPoint,
+                                       const gp_Pnt&        theRefPoint,
+                                       const bool           theMakeGroups)
 {
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
@@ -4003,12 +4485,12 @@ SMESH_MeshEditor::Extrusion_Error
     while ( aItN->more() ) {
       const SMDS_MeshNode* pNode = aItN->next();
       const SMDS_EdgePosition* pEPos =
-       static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
+        static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
       double aT = pEPos->GetUParameter();
       aPrms.push_back( aT );
     }
     //Extrusion_Error err =
-      MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
+    MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
   }
   else if( aS.ShapeType() == TopAbs_WIRE ) {
     list< SMESH_subMesh* > LSM;
@@ -4029,37 +4511,37 @@ SMESH_MeshEditor::Extrusion_Error
       int k = 0;
       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
       for(; itLSM!=LSM.end(); itLSM++) {
-       k++;
-       if(UsedNums.Contains(k)) continue;
-       aTrackEdge = TopoDS::Edge( Edges.Value(k) );
-       SMESH_subMesh* locTrack = *itLSM;
-       SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
-       TopExp::Vertices( aTrackEdge, aV1, aV2 );
-       aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
-       const SMDS_MeshNode* aN1 = aItN->next();
-       aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
-       const SMDS_MeshNode* aN2 = aItN->next();
-       // starting node must be aN1 or aN2
-       if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
-       // 2. Collect parameters on the track edge
-       aPrms.clear();
-       aItN = locMeshDS->GetNodes();
-       while ( aItN->more() ) {
-         const SMDS_MeshNode* pNode = aItN->next();
-         const SMDS_EdgePosition* pEPos =
-           static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
-         double aT = pEPos->GetUParameter();
-         aPrms.push_back( aT );
-       }
-       list<SMESH_MeshEditor_PathPoint> LPP;
-       //Extrusion_Error err =
-          MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
-       LLPPs.push_back(LPP);
-       UsedNums.Add(k);
-       // update startN for search following egde
-       if( aN1->GetID() == startNid ) startNid = aN2->GetID();
-       else startNid = aN1->GetID();
-       break;
+        k++;
+        if(UsedNums.Contains(k)) continue;
+        aTrackEdge = TopoDS::Edge( Edges.Value(k) );
+        SMESH_subMesh* locTrack = *itLSM;
+        SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
+        TopExp::Vertices( aTrackEdge, aV1, aV2 );
+        aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
+        const SMDS_MeshNode* aN1 = aItN->next();
+        aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
+        const SMDS_MeshNode* aN2 = aItN->next();
+        // starting node must be aN1 or aN2
+        if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
+        // 2. Collect parameters on the track edge
+        aPrms.clear();
+        aItN = locMeshDS->GetNodes();
+        while ( aItN->more() ) {
+          const SMDS_MeshNode* pNode = aItN->next();
+          const SMDS_EdgePosition* pEPos =
+            static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
+          double aT = pEPos->GetUParameter();
+          aPrms.push_back( aT );
+        }
+        list<SMESH_MeshEditor_PathPoint> LPP;
+        //Extrusion_Error err =
+        MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
+        LLPPs.push_back(LPP);
+        UsedNums.Add(k);
+        // update startN for search following egde
+        if( aN1->GetID() == startNid ) startNid = aN2->GetID();
+        else startNid = aN1->GetID();
+        break;
       }
     }
     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
@@ -4078,12 +4560,12 @@ SMESH_MeshEditor::Extrusion_Error
       gp_Dir D1 = PP1.Tangent();
       gp_Dir D2 = PP2.Tangent();
       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
-                          (D1.Z()+D2.Z())/2 ) );
+                           (D1.Z()+D2.Z())/2 ) );
       PP1.SetTangent(Dnew);
       fullList.push_back(PP1);
       itPP++;
       for(; itPP!=firstList.end(); itPP++) {
-       fullList.push_back( *itPP );
+        fullList.push_back( *itPP );
       }
       PP1 = fullList.back();
       fullList.pop_back();
@@ -4097,7 +4579,7 @@ SMESH_MeshEditor::Extrusion_Error
   }
 
   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
-                         theHasRefPoint, theRefPoint, theMakeGroups);
+                          theHasRefPoint, theRefPoint, theMakeGroups);
 }
 
 
@@ -4106,15 +4588,15 @@ SMESH_MeshEditor::Extrusion_Error
 //purpose  :
 //=======================================================================
 SMESH_MeshEditor::Extrusion_Error
-  SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
-                                        SMESH_Mesh*          theTrack,
-                                        const SMDS_MeshNode* theN1,
-                                        const bool           theHasAngles,
-                                        list<double>&        theAngles,
-                                        const bool           theLinearVariation,
-                                        const bool           theHasRefPoint,
-                                        const gp_Pnt&        theRefPoint,
-                                         const bool           theMakeGroups)
+SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
+                                       SMESH_Mesh*          theTrack,
+                                       const SMDS_MeshNode* theN1,
+                                       const bool           theHasAngles,
+                                       list<double>&        theAngles,
+                                       const bool           theLinearVariation,
+                                       const bool           theHasRefPoint,
+                                       const gp_Pnt&        theRefPoint,
+                                       const bool           theMakeGroups)
 {
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
@@ -4175,12 +4657,12 @@ SMESH_MeshEditor::Extrusion_Error
       const SMDS_MeshNode* pNode = aItN->next();
       if( pNode==aN1 || pNode==aN2 ) continue;
       const SMDS_EdgePosition* pEPos =
-       static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
+        static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
       double aT = pEPos->GetUParameter();
       aPrms.push_back( aT );
     }
     //Extrusion_Error err =
-      MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
+    MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
   }
   else if( aS.ShapeType() == TopAbs_WIRE ) {
     list< SMESH_subMesh* > LSM;
@@ -4191,8 +4673,8 @@ SMESH_MeshEditor::Extrusion_Error
       if( BRep_Tool::Degenerated(E) ) continue;
       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
       if(SM) {
-       LSM.push_back(SM);
-       Edges.Append(E);
+        LSM.push_back(SM);
+        Edges.Append(E);
       }
     }
     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
@@ -4204,37 +4686,37 @@ SMESH_MeshEditor::Extrusion_Error
       int k = 0;
       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
       for(; itLSM!=LSM.end(); itLSM++) {
-       k++;
-       if(UsedNums.Contains(k)) continue;
-       aTrackEdge = TopoDS::Edge( Edges.Value(k) );
-       SMESH_subMesh* locTrack = *itLSM;
-       SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
-       TopExp::Vertices( aTrackEdge, aV1, aV2 );
-       aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
-       const SMDS_MeshNode* aN1 = aItN->next();
-       aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
-       const SMDS_MeshNode* aN2 = aItN->next();
-       // starting node must be aN1 or aN2
-       if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
-       // 2. Collect parameters on the track edge
-       aPrms.clear();
-       aItN = locMeshDS->GetNodes();
-       while ( aItN->more() ) {
-         const SMDS_MeshNode* pNode = aItN->next();
-         const SMDS_EdgePosition* pEPos =
-           static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
-         double aT = pEPos->GetUParameter();
-         aPrms.push_back( aT );
-       }
-       list<SMESH_MeshEditor_PathPoint> LPP;
-       //Extrusion_Error err =
-          MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
-       LLPPs.push_back(LPP);
-       UsedNums.Add(k);
-       // update startN for search following egde
-       if( aN1->GetID() == startNid ) startNid = aN2->GetID();
-       else startNid = aN1->GetID();
-       break;
+        k++;
+        if(UsedNums.Contains(k)) continue;
+        aTrackEdge = TopoDS::Edge( Edges.Value(k) );
+        SMESH_subMesh* locTrack = *itLSM;
+        SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
+        TopExp::Vertices( aTrackEdge, aV1, aV2 );
+        aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
+        const SMDS_MeshNode* aN1 = aItN->next();
+        aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
+        const SMDS_MeshNode* aN2 = aItN->next();
+        // starting node must be aN1 or aN2
+        if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
+        // 2. Collect parameters on the track edge
+        aPrms.clear();
+        aItN = locMeshDS->GetNodes();
+        while ( aItN->more() ) {
+          const SMDS_MeshNode* pNode = aItN->next();
+          const SMDS_EdgePosition* pEPos =
+            static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
+          double aT = pEPos->GetUParameter();
+          aPrms.push_back( aT );
+        }
+        list<SMESH_MeshEditor_PathPoint> LPP;
+        //Extrusion_Error err =
+        MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
+        LLPPs.push_back(LPP);
+        UsedNums.Add(k);
+        // update startN for search following egde
+        if( aN1->GetID() == startNid ) startNid = aN2->GetID();
+        else startNid = aN1->GetID();
+        break;
       }
     }
     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
@@ -4256,12 +4738,12 @@ SMESH_MeshEditor::Extrusion_Error
       gp_Dir D1 = PP1.Tangent();
       gp_Dir D2 = PP2.Tangent();
       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
-                          (D1.Z()+D2.Z())/2 ) );
+                           (D1.Z()+D2.Z())/2 ) );
       PP1.SetTangent(Dnew);
       fullList.push_back(PP1);
       itPP++;
       for(; itPP!=currList.end(); itPP++) {
-       fullList.push_back( *itPP );
+        fullList.push_back( *itPP );
       }
       PP1 = fullList.back();
       fullList.pop_back();
@@ -4275,7 +4757,7 @@ SMESH_MeshEditor::Extrusion_Error
   }
 
   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
-                         theHasRefPoint, theRefPoint, theMakeGroups);
+                          theHasRefPoint, theRefPoint, theMakeGroups);
 }
 
 
@@ -4285,9 +4767,9 @@ SMESH_MeshEditor::Extrusion_Error
 //=======================================================================
 SMESH_MeshEditor::Extrusion_Error
 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
-                                    const TopoDS_Edge& aTrackEdge,
-                                    bool FirstIsStart,
-                                    list<SMESH_MeshEditor_PathPoint>& LPP)
+                                     const TopoDS_Edge& aTrackEdge,
+                                     bool FirstIsStart,
+                                     list<SMESH_MeshEditor_PathPoint>& LPP)
 {
   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
   aTolVec=1.e-7;
@@ -4340,13 +4822,13 @@ SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
 //=======================================================================
 SMESH_MeshEditor::Extrusion_Error
 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
-                                  list<SMESH_MeshEditor_PathPoint>& fullList,
-                                  const bool theHasAngles,
-                                  list<double>& theAngles,
-                                  const bool theLinearVariation,
-                                  const bool theHasRefPoint,
-                                  const gp_Pnt& theRefPoint,
-                                  const bool theMakeGroups)
+                                   list<SMESH_MeshEditor_PathPoint>& fullList,
+                                   const bool theHasAngles,
+                                   list<double>& theAngles,
+                                   const bool theLinearVariation,
+                                   const bool theHasRefPoint,
+                                   const gp_Pnt& theRefPoint,
+                                   const bool theMakeGroups)
 {
   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
   int aNbTP = fullList.size();
@@ -4395,26 +4877,26 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
   if ( !theHasRefPoint ) {
     aNb = 0;
     aGC.SetCoord( 0.,0.,0. );
-    
+
     itElem = theElements.begin();
     for ( ; itElem != theElements.end(); itElem++ ) {
       const SMDS_MeshElement* elem = *itElem;
-      
+
       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
       while ( itN->more() ) {
-       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
-       aX = node->X();
-       aY = node->Y();
-       aZ = node->Z();
-       
-       if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
-         list<const SMDS_MeshNode*> aLNx;
-         mapNewNodes[node] = aLNx;
-         //
-         gp_XYZ aXYZ( aX, aY, aZ );
-         aGC += aXYZ;
-         ++aNb;
-       }
+        const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
+        aX = node->X();
+        aY = node->Y();
+        aZ = node->Z();
+
+        if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
+          list<const SMDS_MeshNode*> aLNx;
+          mapNewNodes[node] = aLNx;
+          //
+          gp_XYZ aXYZ( aX, aY, aZ );
+          aGC += aXYZ;
+          ++aNb;
+        }
       }
     }
     aGC /= aNb;
@@ -4443,66 +4925,66 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
       ++nodeIndex;
       // check if a node has been already processed
       const SMDS_MeshNode* node =
-       static_cast<const SMDS_MeshNode*>( itN->next() );
+        static_cast<const SMDS_MeshNode*>( itN->next() );
       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
       if ( nIt == mapNewNodes.end() ) {
         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
 
-       // make new nodes
-       aX = node->X();  aY = node->Y(); aZ = node->Z();
-
-       Standard_Real aAngle1x, aAngleT1T0, aTolAng;
-       gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
-       gp_Ax1 anAx1, anAxT1T0;
-       gp_Dir aDT1x, aDT0x, aDT1T0;
-
-       aTolAng=1.e-4;
-
-       aV0x = aV0;
-       aPN0.SetCoord(aX, aY, aZ);
-
-       const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
-       aP0x = aPP0.Pnt();
-       aDT0x= aPP0.Tangent();
-       //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
-
-       for ( j = 1; j < aNbTP; ++j ) {
-         const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
-         aP1x = aPP1.Pnt();
-         aDT1x = aPP1.Tangent();
-         aAngle1x = aPP1.Angle();
-
-         gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
-         // Translation
-         gp_Vec aV01x( aP0x, aP1x );
-         aTrsf.SetTranslation( aV01x );
-
-         // traslated point
-         aV1x = aV0x.Transformed( aTrsf );
-         aPN1 = aPN0.Transformed( aTrsf );
-
-         // rotation 1 [ T1,T0 ]
-         aAngleT1T0=-aDT1x.Angle( aDT0x );
-         if (fabs(aAngleT1T0) > aTolAng) {
-           aDT1T0=aDT1x^aDT0x;
-           anAxT1T0.SetLocation( aV1x );
-           anAxT1T0.SetDirection( aDT1T0 );
-           aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
-
-           aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
-         }
+        // make new nodes
+        aX = node->X();  aY = node->Y(); aZ = node->Z();
+
+        Standard_Real aAngle1x, aAngleT1T0, aTolAng;
+        gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
+        gp_Ax1 anAx1, anAxT1T0;
+        gp_Dir aDT1x, aDT0x, aDT1T0;
+
+        aTolAng=1.e-4;
+
+        aV0x = aV0;
+        aPN0.SetCoord(aX, aY, aZ);
+
+        const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
+        aP0x = aPP0.Pnt();
+        aDT0x= aPP0.Tangent();
+        //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
+
+        for ( j = 1; j < aNbTP; ++j ) {
+          const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
+          aP1x = aPP1.Pnt();
+          aDT1x = aPP1.Tangent();
+          aAngle1x = aPP1.Angle();
+
+          gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
+          // Translation
+          gp_Vec aV01x( aP0x, aP1x );
+          aTrsf.SetTranslation( aV01x );
+
+          // traslated point
+          aV1x = aV0x.Transformed( aTrsf );
+          aPN1 = aPN0.Transformed( aTrsf );
+
+          // rotation 1 [ T1,T0 ]
+          aAngleT1T0=-aDT1x.Angle( aDT0x );
+          if (fabs(aAngleT1T0) > aTolAng) {
+            aDT1T0=aDT1x^aDT0x;
+            anAxT1T0.SetLocation( aV1x );
+            anAxT1T0.SetDirection( aDT1T0 );
+            aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
+
+            aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
+          }
 
-         // rotation 2
-         if ( theHasAngles ) {
-           anAx1.SetLocation( aV1x );
-           anAx1.SetDirection( aDT1x );
-           aTrsfRot.SetRotation( anAx1, aAngle1x );
+          // rotation 2
+          if ( theHasAngles ) {
+            anAx1.SetLocation( aV1x );
+            anAx1.SetDirection( aDT1x );
+            aTrsfRot.SetRotation( anAx1, aAngle1x );
 
-           aPN1 = aPN1.Transformed( aTrsfRot );
-         }
+            aPN1 = aPN1.Transformed( aTrsfRot );
+          }
 
-         // make new node
+          // make new node
           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
             // create additional node
             double x = ( aPN1.X() + aPN0.X() )/2.;
@@ -4513,19 +4995,19 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
             srcNodes.Append( node );
             listNewNodes.push_back( newNode );
           }
-         aX = aPN1.X();
-         aY = aPN1.Y();
-         aZ = aPN1.Z();
-         const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
+          aX = aPN1.X();
+          aY = aPN1.Y();
+          aZ = aPN1.Z();
+          const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
           myLastCreatedNodes.Append(newNode);
           srcNodes.Append( node );
-         listNewNodes.push_back( newNode );
+          listNewNodes.push_back( newNode );
 
-         aPN0 = aPN1;
-         aP0x = aP1x;
-         aV0x = aV1x;
-         aDT0x = aDT1x;
-       }
+          aPN0 = aPN1;
+          aP0x = aP1x;
+          aV0x = aV1x;
+          aDT0x = aDT1x;
+        }
       }
 
       else {
@@ -4580,7 +5062,7 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
 //purpose  : auxilary for ExtrusionAlongTrack
 //=======================================================================
 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
-                                           list<double>& Angles)
+                                            list<double>& Angles)
 {
   int nbAngles = Angles.size();
   if( nbSteps > nbAngles ) {
@@ -4599,19 +5081,19 @@ void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
       double angCurFloor  = floor( angCur );
       double angPrevFloor = floor( angPrev );
       if ( angPrevFloor == angCurFloor )
-       angle = rAn2St * theAngles[ int( angCurFloor ) ];
+        angle = rAn2St * theAngles[ int( angCurFloor ) ];
       else {
-       int iP = int( angPrevFloor );
-       double angPrevCeil = ceil(angPrev);
-       angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
-          
-       int iC = int( angCurFloor );
-       if ( iC < nbAngles )
-         angle += ( angCur - angCurFloor ) * theAngles[ iC ];
-       
-       iP = int( angPrevCeil );
-       while ( iC-- > iP )
-         angle += theAngles[ iC ];
+        int iP = int( angPrevFloor );
+        double angPrevCeil = ceil(angPrev);
+        angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
+
+        int iC = int( angCurFloor );
+        if ( iC < nbAngles )
+          angle += ( angCur - angCurFloor ) * theAngles[ iC ];
+
+        iP = int( angPrevCeil );
+        while ( iC-- > iP )
+          angle += theAngles[ iC ];
       }
       res.push_back(angle);
       angPrev = angCur;
@@ -4665,7 +5147,7 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
   SMESHDS_Mesh* aMesh    = GetMeshDS();
-  
+
 
   // map old node to new one
   TNodeNodeMap nodeMap;
@@ -4747,7 +5229,7 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
     REV_FACE    = 3,
     REV_HEXA    = 4,  //  = nbNodes - 4
     FORWARD     = 5
-    };
+  };
   int index[][8] = {
     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
@@ -4848,18 +5330,18 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
           }
         }
         break;
-    default:;
+      default:;
+      }
+      continue;
     }
-    continue;
-  }
 
-  // Regular elements
-  int* i = index[ FORWARD ];
-  if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
-    if ( elemType == SMDSAbs_Face )
-      i = index[ REV_FACE ];
-    else
-      i = index[ nbNodes - 4 ];
+    // Regular elements
+    int* i = index[ FORWARD ];
+    if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
+      if ( elemType == SMDSAbs_Face )
+        i = index[ REV_FACE ];
+      else
+        i = index[ nbNodes - 4 ];
 
     if(elem->IsQuadratic()) {
       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
@@ -4940,263 +5422,1525 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
   return newGroupIDs;
 }
 
+
 //=======================================================================
-/*!
- * \brief Create groups of elements made during transformation
- * \param nodeGens - nodes making corresponding myLastCreatedNodes
- * \param elemGens - elements making corresponding myLastCreatedElems
- * \param postfix - to append to names of new groups
- */
+//function : Scale
+//purpose  :
 //=======================================================================
 
 SMESH_MeshEditor::PGroupIDs
-SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
-                                 const SMESH_SequenceOfElemPtr& elemGens,
-                                 const std::string&             postfix,
-                                 SMESH_Mesh*                    targetMesh)
+SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
+                         const gp_Pnt&            thePoint,
+                         const std::list<double>& theScaleFact,
+                         const bool         theCopy,
+                         const bool         theMakeGroups,
+                         SMESH_Mesh*        theTargetMesh)
 {
-  PGroupIDs newGroupIDs( new list<int> );
-  SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
 
-  // Sort existing groups by types and collect their names
+  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
+  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
+  SMESHDS_Mesh* aMesh    = GetMeshDS();
 
-  // to store an old group and a generated new one
-  typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
-  vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
-  // group names
-  set< string > groupNames;
-  //
-  SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
-  SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
-  while ( groupIt->more() ) {
-    SMESH_Group * group = groupIt->next();
-    if ( !group ) continue;
-    SMESHDS_GroupBase* groupDS = group->GetGroupDS();
-    if ( !groupDS || groupDS->IsEmpty() ) continue;
-    groupNames.insert( group->GetName() );
-    groupDS->SetStoreName( group->GetName() );
-    groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
+  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
+  std::list<double>::const_iterator itS = theScaleFact.begin();
+  scaleX = (*itS);
+  if(theScaleFact.size()==1) {
+    scaleY = (*itS);
+    scaleZ= (*itS);
+  }
+  if(theScaleFact.size()==2) {
+    itS++;
+    scaleY = (*itS);
+    scaleZ= (*itS);
   }
+  if(theScaleFact.size()>2) {
+    itS++;
+    scaleY = (*itS);
+    itS++;
+    scaleZ= (*itS);
+  }
+  
+  // map old node to new one
+  TNodeNodeMap nodeMap;
 
-  // Groups creation
+  // elements sharing moved nodes; those of them which have all
+  // nodes mirrored but are not in theElems are to be reversed
+  TIDSortedElemSet inverseElemSet;
 
-  // loop on nodes and elements
-  for ( int isNodes = 0; isNodes < 2; ++isNodes )
-  {
-    const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
-    const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
-    if ( gens.Length() != elems.Length() )
-      throw SALOME_Exception(LOCALIZED("invalid args"));
+  // source elements for each generated one
+  SMESH_SequenceOfElemPtr srcElems, srcNodes;
 
-    // loop on created elements
-    for (int iElem = 1; iElem <= elems.Length(); ++iElem )
-    {
-      const SMDS_MeshElement* sourceElem = gens( iElem );
-      if ( !sourceElem ) {
-        MESSAGE("generateGroups(): NULL source element");
+  // loop on theElems
+  TIDSortedElemSet::iterator itElem;
+  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+    const SMDS_MeshElement* elem = *itElem;
+    if ( !elem )
+      continue;
+
+    // loop on elem nodes
+    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+    while ( itN->more() ) {
+
+      // check if a node has been already transformed
+      const SMDS_MeshNode* node = cast2Node( itN->next() );
+      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
+        nodeMap.insert( make_pair ( node, node ));
+      if ( !n2n_isnew.second )
         continue;
+
+      //double coord[3];
+      //coord[0] = node->X();
+      //coord[1] = node->Y();
+      //coord[2] = node->Z();
+      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
+      double dx = (node->X() - thePoint.X()) * scaleX;
+      double dy = (node->Y() - thePoint.Y()) * scaleY;
+      double dz = (node->Z() - thePoint.Z()) * scaleZ;
+      if ( theTargetMesh ) {
+        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
+        const SMDS_MeshNode * newNode =
+          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
+        n2n_isnew.first->second = newNode;
+        myLastCreatedNodes.Append(newNode);
+        srcNodes.Append( node );
       }
-      list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
-      if ( groupsOldNew.empty() ) {
-        while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
-          ++iElem; // skip all elements made by sourceElem
-        continue;
+      else if ( theCopy ) {
+        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+        const SMDS_MeshNode * newNode =
+          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
+        n2n_isnew.first->second = newNode;
+        myLastCreatedNodes.Append(newNode);
+        srcNodes.Append( node );
+      }
+      else {
+        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
+        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
+        // node position on shape becomes invalid
+        const_cast< SMDS_MeshNode* > ( node )->SetPosition
+          ( SMDS_SpacePosition::originSpacePosition() );
       }
-      // collect all elements made by sourceElem
-      list< const SMDS_MeshElement* > resultElems;
-      if ( const SMDS_MeshElement* resElem = elems( iElem ))
-        if ( resElem != sourceElem )
-          resultElems.push_back( resElem );
-      while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
-        if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
-          if ( resElem != sourceElem )
-            resultElems.push_back( resElem );
-      // do not generate element groups from node ones
-      if ( sourceElem->GetType() == SMDSAbs_Node &&
-           elems( iElem )->GetType() != SMDSAbs_Node )
-        continue;
 
-      // add resultElems to groups made by ones the sourceElem belongs to
-      list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
-      for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
-      {
-        SMESHDS_GroupBase* oldGroup = gOldNew->first;
-        if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
-        {
-          SMDS_MeshGroup* & newGroup = gOldNew->second;
-          if ( !newGroup )// create a new group
-          {
-            // make a name
-            string name = oldGroup->GetStoreName();
-            if ( !targetMesh ) {
-              name += "_";
-              name += postfix;
-              int nb = 0;
-              while ( !groupNames.insert( name ).second ) // name exists
-              {
-                if ( nb == 0 ) {
-                  name += "_1";
-                }
-                else {
-                  TCollection_AsciiString nbStr(nb+1);
-                  name.resize( name.rfind('_')+1 );
-                  name += nbStr.ToCString();
-                }
-                ++nb;
-              }
-            }
-            // make a group
-            int id;
-            SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
-                                                 name.c_str(), id );
-            SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
-            newGroup = & groupDS->SMDSGroup();
-            newGroupIDs->push_back( id );
-          }
+      // keep inverse elements
+      //if ( !theCopy && !theTargetMesh && needReverse ) {
+      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
+      //  while ( invElemIt->more() ) {
+      //    const SMDS_MeshElement* iel = invElemIt->next();
+      //    inverseElemSet.insert( iel );
+      //  }
+      //}
+    }
+  }
 
-          // fill in a new group
-          list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
-          for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
-            newGroup->Add( *resElemIt );
-        }
-      }
-    } // loop on created elements
-  }// loop on nodes and elements
+  // either create new elements or reverse mirrored ones
+  //if ( !theCopy && !needReverse && !theTargetMesh )
+  if ( !theCopy && !theTargetMesh )
+    return PGroupIDs();
 
-  return newGroupIDs;
-}
+  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
+  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
+    theElems.insert( *invElemIt );
 
-//=======================================================================
-//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 using
-//           an Octree algorithm
-//=======================================================================
+  // replicate or reverse elements
 
-void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
-                                            const double                theTolerance,
-                                            TListOfListOfNodes &        theGroupsOfNodes)
-{
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  enum {
+    REV_TETRA   = 0,  //  = nbNodes - 4
+    REV_PYRAMID = 1,  //  = nbNodes - 4
+    REV_PENTA   = 2,  //  = nbNodes - 4
+    REV_FACE    = 3,
+    REV_HEXA    = 4,  //  = nbNodes - 4
+    FORWARD     = 5
+  };
+  int index[][8] = {
+    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
+    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
+    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
+    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
+    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
+    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
+  };
 
-  set<const SMDS_MeshNode*> nodes;
-  if ( theNodes.empty() )
-  { // get all nodes in the mesh
-    SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
-    while ( nIt->more() )
-      nodes.insert( nodes.end(),nIt->next());
-  }
-  else
-    nodes=theNodes;
-  SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
+  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
+  {
+    const SMDS_MeshElement* elem = *itElem;
+    if ( !elem || elem->GetType() == SMDSAbs_Node )
+      continue;
 
-}
+    int nbNodes = elem->NbNodes();
+    int elemType = elem->GetType();
 
-//=======================================================================
+    if (elem->IsPoly()) {
+      // Polygon or Polyhedral Volume
+      switch ( elemType ) {
+      case SMDSAbs_Face:
+        {
+          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
+          int iNode = 0;
+          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+          while (itN->more()) {
+            const SMDS_MeshNode* node =
+              static_cast<const SMDS_MeshNode*>(itN->next());
+            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
+            if (nodeMapIt == nodeMap.end())
+              break; // not all nodes transformed
+            //if (needReverse) {
+            //  // reverse mirrored faces and volumes
+            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
+            //} else {
+            poly_nodes[iNode] = (*nodeMapIt).second;
+            //}
+            iNode++;
+          }
+          if ( iNode != nbNodes )
+            continue; // not all nodes transformed
+
+          if ( theTargetMesh ) {
+            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
+            srcElems.Append( elem );
+          }
+          else if ( theCopy ) {
+            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
+            srcElems.Append( elem );
+          }
+          else {
+            aMesh->ChangePolygonNodes(elem, poly_nodes);
+          }
+        }
+        break;
+      case SMDSAbs_Volume:
+        {
+          // ATTENTION: Reversing is not yet done!!!
+          const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
+            dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
+          if (!aPolyedre) {
+            MESSAGE("Warning: bad volumic element");
+            continue;
+          }
+
+          vector<const SMDS_MeshNode*> poly_nodes;
+          vector<int> quantities;
+
+          bool allTransformed = true;
+          int nbFaces = aPolyedre->NbFaces();
+          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
+            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
+            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
+              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
+              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
+              if (nodeMapIt == nodeMap.end()) {
+                allTransformed = false; // not all nodes transformed
+              } else {
+                poly_nodes.push_back((*nodeMapIt).second);
+              }
+            }
+            quantities.push_back(nbFaceNodes);
+          }
+          if ( !allTransformed )
+            continue; // not all nodes transformed
+
+          if ( theTargetMesh ) {
+            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
+            srcElems.Append( elem );
+          }
+          else if ( theCopy ) {
+            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
+            srcElems.Append( elem );
+          }
+          else {
+            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
+          }
+        }
+        break;
+      default:;
+      }
+      continue;
+    }
+
+    // Regular elements
+    int* i = index[ FORWARD ];
+    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
+    //  if ( elemType == SMDSAbs_Face )
+    //    i = index[ REV_FACE ];
+    //  else
+    //    i = index[ nbNodes - 4 ];
+
+    if(elem->IsQuadratic()) {
+      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
+      i = anIds;
+      //if(needReverse) {
+      //  if(nbNodes==3) { // quadratic edge
+      //    static int anIds[] = {1,0,2};
+      //    i = anIds;
+      //  }
+      //  else if(nbNodes==6) { // quadratic triangle
+      //    static int anIds[] = {0,2,1,5,4,3};
+      //    i = anIds;
+      //  }
+      //  else if(nbNodes==8) { // quadratic quadrangle
+      //    static int anIds[] = {0,3,2,1,7,6,5,4};
+      //    i = anIds;
+      //  }
+      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
+      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
+      //    i = anIds;
+      //  }
+      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
+      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
+      //    i = anIds;
+      //  }
+      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
+      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
+      //    i = anIds;
+      //  }
+      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
+      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
+      //    i = anIds;
+      //  }
+      //}
+    }
+
+    // find transformed nodes
+    vector<const SMDS_MeshNode*> nodes(nbNodes);
+    int iNode = 0;
+    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+    while ( itN->more() ) {
+      const SMDS_MeshNode* node =
+        static_cast<const SMDS_MeshNode*>( itN->next() );
+      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
+      if ( nodeMapIt == nodeMap.end() )
+        break; // not all nodes transformed
+      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
+    }
+    if ( iNode != nbNodes )
+      continue; // not all nodes transformed
+
+    if ( theTargetMesh ) {
+      if ( SMDS_MeshElement* copy =
+           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
+        myLastCreatedElems.Append( copy );
+        srcElems.Append( elem );
+      }
+    }
+    else if ( theCopy ) {
+      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
+        myLastCreatedElems.Append( copy );
+        srcElems.Append( elem );
+      }
+    }
+    else {
+      // reverse element as it was reversed by transformation
+      if ( nbNodes > 2 )
+        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
+    }
+  }
+
+  PGroupIDs newGroupIDs;
+
+  if ( theMakeGroups && theCopy ||
+       theMakeGroups && theTargetMesh ) {
+    string groupPostfix = "scaled";
+    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
+  }
+
+  return newGroupIDs;
+}
+
+
+//=======================================================================
+/*!
+ * \brief Create groups of elements made during transformation
+ * \param nodeGens - nodes making corresponding myLastCreatedNodes
+ * \param elemGens - elements making corresponding myLastCreatedElems
+ * \param postfix - to append to names of new groups
+ */
+//=======================================================================
+
+SMESH_MeshEditor::PGroupIDs
+SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
+                                 const SMESH_SequenceOfElemPtr& elemGens,
+                                 const std::string&             postfix,
+                                 SMESH_Mesh*                    targetMesh)
+{
+  PGroupIDs newGroupIDs( new list<int> );
+  SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
+
+  // Sort existing groups by types and collect their names
+
+  // to store an old group and a generated new one
+  typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
+  vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
+  // group names
+  set< string > groupNames;
+  //
+  SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
+  SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
+  while ( groupIt->more() ) {
+    SMESH_Group * group = groupIt->next();
+    if ( !group ) continue;
+    SMESHDS_GroupBase* groupDS = group->GetGroupDS();
+    if ( !groupDS || groupDS->IsEmpty() ) continue;
+    groupNames.insert( group->GetName() );
+    groupDS->SetStoreName( group->GetName() );
+    groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
+  }
+
+  // Groups creation
+
+  // loop on nodes and elements
+  for ( int isNodes = 0; isNodes < 2; ++isNodes )
+  {
+    const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
+    const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
+    if ( gens.Length() != elems.Length() )
+      throw SALOME_Exception(LOCALIZED("invalid args"));
+
+    // loop on created elements
+    for (int iElem = 1; iElem <= elems.Length(); ++iElem )
+    {
+      const SMDS_MeshElement* sourceElem = gens( iElem );
+      if ( !sourceElem ) {
+        MESSAGE("generateGroups(): NULL source element");
+        continue;
+      }
+      list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
+      if ( groupsOldNew.empty() ) {
+        while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
+          ++iElem; // skip all elements made by sourceElem
+        continue;
+      }
+      // collect all elements made by sourceElem
+      list< const SMDS_MeshElement* > resultElems;
+      if ( const SMDS_MeshElement* resElem = elems( iElem ))
+        if ( resElem != sourceElem )
+          resultElems.push_back( resElem );
+      while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
+        if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
+          if ( resElem != sourceElem )
+            resultElems.push_back( resElem );
+      // do not generate element groups from node ones
+      if ( sourceElem->GetType() == SMDSAbs_Node &&
+           elems( iElem )->GetType() != SMDSAbs_Node )
+        continue;
+
+      // add resultElems to groups made by ones the sourceElem belongs to
+      list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
+      for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
+      {
+        SMESHDS_GroupBase* oldGroup = gOldNew->first;
+        if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
+        {
+          SMDS_MeshGroup* & newGroup = gOldNew->second;
+          if ( !newGroup )// create a new group
+          {
+            // make a name
+            string name = oldGroup->GetStoreName();
+            if ( !targetMesh ) {
+              name += "_";
+              name += postfix;
+              int nb = 0;
+              while ( !groupNames.insert( name ).second ) // name exists
+              {
+                if ( nb == 0 ) {
+                  name += "_1";
+                }
+                else {
+                  TCollection_AsciiString nbStr(nb+1);
+                  name.resize( name.rfind('_')+1 );
+                  name += nbStr.ToCString();
+                }
+                ++nb;
+              }
+            }
+            // make a group
+            int id;
+            SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
+                                                 name.c_str(), id );
+            SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
+            newGroup = & groupDS->SMDSGroup();
+            newGroupIDs->push_back( id );
+          }
+
+          // fill in a new group
+          list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
+          for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
+            newGroup->Add( *resElemIt );
+        }
+      }
+    } // loop on created elements
+  }// loop on nodes and elements
+
+  return newGroupIDs;
+}
+
+//================================================================================
+/*!
+ * \brief Return list of group of nodes close to each other within theTolerance
+ *        Search among theNodes or in the whole mesh if theNodes is empty using
+ *        an Octree algorithm
+ */
+//================================================================================
+
+void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
+                                            const double                theTolerance,
+                                            TListOfListOfNodes &        theGroupsOfNodes)
+{
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
+  set<const SMDS_MeshNode*> nodes;
+  if ( theNodes.empty() )
+  { // get all nodes in the mesh
+    SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
+    while ( nIt->more() )
+      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
-{
+struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
+{
+  //---------------------------------------------------------------------
+  /*!
+   * \brief Constructor
+   */
+  SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
+  {
+    myMesh = ( SMESHDS_Mesh* ) theMesh;
+
+    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) ;
+
+    // get max size of a leaf box
+    SMESH_OctreeNode* tree = myOctreeNode;
+    while ( !tree->isLeaf() )
+    {
+      SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
+      if ( cIt->more() )
+        tree = cIt->next();
+    }
+    myHalfLeafSize = tree->maxSize() / 2.;
+  }
+
+  //---------------------------------------------------------------------
+  /*!
+   * \brief Move node and update myOctreeNode accordingly
+   */
+  void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
+  {
+    myOctreeNode->UpdateByMoveNode( node, toPnt );
+    myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
+  }
+
+  //---------------------------------------------------------------------
+  /*!
+   * \brief Do it's job
+   */
+  const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
+  {
+    SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
+    map<double, const SMDS_MeshNode*> dist2Nodes;
+    myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
+    if ( !dist2Nodes.empty() )
+      return dist2Nodes.begin()->second;
+    list<const SMDS_MeshNode*> nodes;
+    //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
+
+    double minSqDist = DBL_MAX;
+    if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
+    {
+      // sort leafs by their distance from thePnt
+      typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
+      TDistTreeMap treeMap;
+      list< SMESH_OctreeNode* > treeList;
+      list< SMESH_OctreeNode* >::iterator trIt;
+      treeList.push_back( myOctreeNode );
+
+      SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
+      for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
+      {
+        SMESH_OctreeNode* tree = *trIt;
+        if ( !tree->isLeaf() ) // put children to the queue
+        {
+          if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue;
+          SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
+          while ( cIt->more() )
+            treeList.push_back( cIt->next() );
+        }
+        else if ( tree->NbNodes() ) // put a tree to the treeMap
+        {
+          const Bnd_B3d& box = tree->getBox();
+          double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
+          pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
+          if ( !it_in.second ) // not unique distance to box center
+            treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
+        }
+      }
+      // find distance after which there is no sense to check tree's
+      double sqLimit = DBL_MAX;
+      TDistTreeMap::iterator sqDist_tree = treeMap.begin();
+      if ( treeMap.size() > 5 ) {
+        SMESH_OctreeNode* closestTree = sqDist_tree->second;
+        const Bnd_B3d& box = closestTree->getBox();
+        double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
+        sqLimit = limit * limit;
+      }
+      // get all nodes from trees
+      for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
+        if ( sqDist_tree->first > sqLimit )
+          break;
+        SMESH_OctreeNode* tree = sqDist_tree->second;
+        tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
+      }
+    }
+    // find closest among nodes
+    minSqDist = DBL_MAX;
+    const SMDS_MeshNode* closestNode = 0;
+    list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
+    for ( ; nIt != nodes.end(); ++nIt ) {
+      double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
+      if ( minSqDist > sqDist ) {
+        closestNode = *nIt;
+        minSqDist = sqDist;
+      }
+    }
+    return closestNode;
+  }
+
+  //---------------------------------------------------------------------
+  /*!
+   * \brief Destructor
+   */
+  ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
+
+  //---------------------------------------------------------------------
+  /*!
+   * \brief Return the node tree
+   */
+  const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
+
+private:
+  SMESH_OctreeNode* myOctreeNode;
+  SMESHDS_Mesh*     myMesh;
+  double            myHalfLeafSize; // max size of a leaf box
+};
+
+//=======================================================================
+/*!
+ * \brief Return SMESH_NodeSearcher
+ */
+//=======================================================================
+
+SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
+{
+  return new SMESH_NodeSearcherImpl( GetMeshDS() );
+}
+
+// ========================================================================
+namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
+{
+  const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
+  const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
+  const double NodeRadius = 1e-9;  // to enlarge bnd box of element
+
+  //=======================================================================
+  /*!
+   * \brief Octal tree of bounding boxes of elements
+   */
+  //=======================================================================
+
+  class ElementBndBoxTree : public SMESH_Octree
+  {
+  public:
+
+    ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
+    void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
+    void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
+    ~ElementBndBoxTree();
+
+  protected:
+    ElementBndBoxTree() {}
+    SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
+    void buildChildrenData();
+    Bnd_B3d* buildRootBox();
+  private:
+    //!< Bounding box of element
+    struct ElementBox : public Bnd_B3d
+    {
+      const SMDS_MeshElement* _element;
+      int                     _refCount; // an ElementBox can be included in several tree branches
+      ElementBox(const SMDS_MeshElement* elem);
+    };
+    vector< ElementBox* > _elements;
+  };
+
+  //================================================================================
+  /*!
+   * \brief ElementBndBoxTree creation
+   */
+  //================================================================================
+
+  ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
+    :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
+  {
+    int nbElems = mesh.GetMeshInfo().NbElements( elemType );
+    _elements.reserve( nbElems );
+
+    SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
+    while ( elemIt->more() )
+      _elements.push_back( new ElementBox( elemIt->next() ));
+
+    if ( _elements.size() > MaxNbElemsInLeaf )
+      compute();
+    else
+      myIsLeaf = true;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Destructor
+   */
+  //================================================================================
+
+  ElementBndBoxTree::~ElementBndBoxTree()
+  {
+    for ( int i = 0; i < _elements.size(); ++i )
+      if ( --_elements[i]->_refCount <= 0 )
+        delete _elements[i];
+  }
+
+  //================================================================================
+  /*!
+   * \brief Return the maximal box
+   */
+  //================================================================================
+
+  Bnd_B3d* ElementBndBoxTree::buildRootBox()
+  {
+    Bnd_B3d* box = new Bnd_B3d;
+    for ( int i = 0; i < _elements.size(); ++i )
+      box->Add( *_elements[i] );
+    return box;
+  }
+
+  //================================================================================
   /*!
-   * \brief Constructor
+   * \brief Redistrubute element boxes among children
    */
-  SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
+  //================================================================================
+
+  void ElementBndBoxTree::buildChildrenData()
   {
-    set<const SMDS_MeshNode*> nodes;
-    if ( theMesh ) {
-      SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
-      while ( nIt->more() )
-        nodes.insert( nodes.end(), nIt->next() );
+    for ( int i = 0; i < _elements.size(); ++i )
+    {
+      for (int j = 0; j < 8; j++)
+      {
+        if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
+        {
+          _elements[i]->_refCount++;
+          ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
+        }
+      }
+      _elements[i]->_refCount--;
+    }
+    _elements.clear();
+
+    for (int j = 0; j < 8; j++)
+    {
+      ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
+      if ( child->_elements.size() <= MaxNbElemsInLeaf )
+        child->myIsLeaf = true;
+
+      if ( child->_elements.capacity() - child->_elements.size() > 1000 )
+        child->_elements.resize( child->_elements.size() ); // compact
     }
-    myOctreeNode = new SMESH_OctreeNode(nodes) ;
   }
+
+  //================================================================================
   /*!
-   * \brief Do it's job
+   * \brief Return elements which can include the point
    */
-  const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
+  //================================================================================
+
+  void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
+                                                TIDSortedElemSet& foundElems)
   {
-    SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
-    list<const SMDS_MeshNode*> nodes;
-    const double precision = 1e-6;
-    //myOctreeNode->NodesAround( &tgtNode, &nodes, precision );
+    if ( level() && getBox().IsOut( point.XYZ() ))
+      return;
 
-    double minSqDist = DBL_MAX;
-    Bnd_B3d box;
-    if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
+    if ( isLeaf() )
     {
-      // 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)
+      for ( int i = 0; i < _elements.size(); ++i )
+        if ( !_elements[i]->IsOut( point.XYZ() ))
+          foundElems.insert( _elements[i]->_element );
+    }
+    else
+    {
+      for (int i = 0; i < 8; i++)
+        ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
+    }
+  }
+
+  //================================================================================
+  /*!
+   * \brief Return elements which can be intersected by the line
+   */
+  //================================================================================
+
+  void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
+                                               TIDSortedElemSet& foundElems)
+  {
+    if ( level() && getBox().IsOut( line ))
+      return;
+
+    if ( isLeaf() )
+    {
+      for ( int i = 0; i < _elements.size(); ++i )
+        if ( !_elements[i]->IsOut( line ))
+          foundElems.insert( _elements[i]->_element );
+    }
+    else
+    {
+      for (int i = 0; i < 8; i++)
+        ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
+    }
+  }
+
+  //================================================================================
+  /*!
+   * \brief Construct the element box
+   */
+  //================================================================================
+
+  ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
+  {
+    _element  = elem;
+    _refCount = 1;
+    SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
+    while ( nIt->more() )
+      Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
+    Enlarge( NodeRadius );
+  }
+
+} // namespace
+
+//=======================================================================
+/*!
+ * \brief Implementation of search for the elements by point and
+ *        of classification of point in 2D mesh
+ */
+//=======================================================================
+
+struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
+{
+  SMESHDS_Mesh*                _mesh;
+  ElementBndBoxTree*           _ebbTree;
+  SMESH_NodeSearcherImpl*      _nodeSearcher;
+  SMDSAbs_ElementType          _elementType;
+  double                       _tolerance;
+  bool                         _outerFacesFound;
+  set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
+
+  SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
+    : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
+  ~SMESH_ElementSearcherImpl()
+  {
+    if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
+    if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
+  }
+  virtual int FindElementsByPoint(const gp_Pnt&                      point,
+                                  SMDSAbs_ElementType                type,
+                                  vector< const SMDS_MeshElement* >& foundElements);
+  virtual TopAbs_State GetPointState(const gp_Pnt& point);
+
+  double getTolerance();
+  bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
+                            const double tolerance, double & param);
+  void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
+  bool isOuterBoundary(const SMDS_MeshElement* face) const
+  {
+    return _outerFaces.empty() || _outerFaces.count(face);
+  }
+  struct TInters //!< data of intersection of the line and the mesh face used in GetPointState()
+  {
+    const SMDS_MeshElement* _face;
+    gp_Vec                  _faceNorm;
+    bool                    _coincides; //!< the line lays in face plane
+    TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
+      : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
+  };
+  struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
+  {
+    SMESH_TLink      _link;
+    TIDSortedElemSet _faces;
+    TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
+      : _link( n1, n2 ), _faces( &face, &face + 1) {}
+  };
+};
+
+ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
+{
+  return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
+             << ", _coincides="<<i._coincides << ")";
+}
+
+//=======================================================================
+/*!
+ * \brief define tolerance for search
+ */
+//=======================================================================
+
+double SMESH_ElementSearcherImpl::getTolerance()
+{
+  if ( _tolerance < 0 )
+  {
+    const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
+
+    _tolerance = 0;
+    if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
+    {
+      double boxSize = _nodeSearcher->getTree()->maxSize();
+      _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
+    }
+    else if ( _ebbTree && meshInfo.NbElements() > 0 )
+    {
+      double boxSize = _ebbTree->maxSize();
+      _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
+    }
+    if ( _tolerance == 0 )
+    {
+      // define tolerance by size of a most complex element
+      int complexType = SMDSAbs_Volume;
+      while ( complexType > SMDSAbs_All &&
+              meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
+        --complexType;
+      if ( complexType == SMDSAbs_All ) return 0; // empty mesh
+
+      double elemSize;
+      if ( complexType == int( SMDSAbs_Node ))
       {
-        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() );
+        SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
+        elemSize = 1;
+        if ( meshInfo.NbNodes() > 2 )
+          elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
+      }
+      else
+      {
+        const SMDS_MeshElement* elem =
+          _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
+        SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
+        SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
+        while ( nodeIt->more() )
+        {
+          double dist = n1.Distance( cast2Node( nodeIt->next() ));
+          elemSize = max( dist, elemSize );
         }
-        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 ));
+      }
+      _tolerance = 1e-6 * elemSize;
+    }
+  }
+  return _tolerance;
+}
+
+//================================================================================
+/*!
+ * \brief Find intersection of the line and an edge of face and return parameter on line
+ */
+//================================================================================
+
+bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
+                                                     const SMDS_MeshElement* face,
+                                                     const double            tol,
+                                                     double &                param)
+{
+  int nbInts = 0;
+  param = 0;
+
+  GeomAPI_ExtremaCurveCurve anExtCC;
+  Handle(Geom_Curve) lineCurve = new Geom_Line( line );
+  
+  int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
+  for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
+  {
+    GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
+                         SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
+    anExtCC.Init( lineCurve, edge);
+    if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
+    {
+      Quantity_Parameter pl, pe;
+      anExtCC.LowerDistanceParameters( pl, pe );
+      param += pl;
+      if ( ++nbInts == 2 )
+        break;
+    }
+  }
+  if ( nbInts > 0 ) param /= nbInts;
+  return nbInts > 0;
+}
+//================================================================================
+/*!
+ * \brief Find all faces belonging to the outer boundary of mesh
+ */
+//================================================================================
+
+void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
+{
+  if ( _outerFacesFound ) return;
+
+  // Collect all outer faces by passing from one outer face to another via their links
+  // and BTW find out if there are internal faces at all.
+
+  // checked links and links where outer boundary meets internal one
+  set< SMESH_TLink > visitedLinks, seamLinks;
+
+  // links to treat with already visited faces sharing them
+  list < TFaceLink > startLinks;
+
+  // load startLinks with the first outerFace
+  startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
+  _outerFaces.insert( outerFace );
+
+  TIDSortedElemSet emptySet;
+  while ( !startLinks.empty() )
+  {
+    const SMESH_TLink& link  = startLinks.front()._link;
+    TIDSortedElemSet&  faces = startLinks.front()._faces;
+
+    outerFace = *faces.begin();
+    // find other faces sharing the link
+    const SMDS_MeshElement* f;
+    while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
+      faces.insert( f );
+
+    // select another outer face among the found 
+    const SMDS_MeshElement* outerFace2 = 0;
+    if ( faces.size() == 2 )
+    {
+      outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
+    }
+    else if ( faces.size() > 2 )
+    {
+      seamLinks.insert( link );
+
+      // link direction within the outerFace
+      gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
+                   SMESH_MeshEditor::TNodeXYZ( link.node2()));
+      int i1 = outerFace->GetNodeIndex( link.node1() );
+      int i2 = outerFace->GetNodeIndex( link.node2() );
+      bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
+      if ( rev ) n1n2.Reverse();
+      // outerFace normal
+      gp_XYZ ofNorm, fNorm;
+      if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
+      {
+        // direction from the link inside outerFace
+        gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
+        // sort all other faces by angle with the dirInOF
+        map< double, const SMDS_MeshElement* > angle2Face;
+        set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
+        for ( ; face != faces.end(); ++face )
+        {
+          if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
+            continue;
+          gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
+          double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
+          if ( angle < 0 ) angle += 2*PI;
+          angle2Face.insert( make_pair( angle, *face ));
         }
+        if ( !angle2Face.empty() )
+          outerFace2 = angle2Face.begin()->second;
       }
-      // 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;
+    }
+    // store the found outer face and add its links to continue seaching from
+    if ( outerFace2 )
+    {
+      _outerFaces.insert( outerFace );
+      int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
+      for ( int i = 0; i < nbNodes; ++i )
+      {
+        SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
+        if ( visitedLinks.insert( link2 ).second )
+          startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
       }
-      // 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 );
+    }
+    startLinks.pop_front();
+  }
+  _outerFacesFound = true;
+
+  if ( !seamLinks.empty() )
+  {
+    // There are internal boundaries touching the outher one,
+    // find all faces of internal boundaries in order to find
+    // faces of boundaries of holes, if any.
+    
+  }
+  else
+  {
+    _outerFaces.clear();
+  }
+}
+
+//=======================================================================
+/*!
+ * \brief Find elements of given type where the given point is IN or ON.
+ *        Returns nb of found elements and elements them-selves.
+ *
+ * 'ALL' type means elements of any type excluding nodes and 0D elements
+ */
+//=======================================================================
+
+int SMESH_ElementSearcherImpl::
+FindElementsByPoint(const gp_Pnt&                      point,
+                    SMDSAbs_ElementType                type,
+                    vector< const SMDS_MeshElement* >& foundElements)
+{
+  foundElements.clear();
+
+  double tolerance = getTolerance();
+
+  // =================================================================================
+  if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
+  {
+    if ( !_nodeSearcher )
+      _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
+
+    const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
+    if ( !closeNode ) return foundElements.size();
+
+    if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
+      return foundElements.size(); // to far from any node
+
+    if ( type == SMDSAbs_Node )
+    {
+      foundElements.push_back( closeNode );
+    }
+    else
+    {
+      SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
+      while ( elemIt->more() )
+        foundElements.push_back( elemIt->next() );
+    }
+  }
+  // =================================================================================
+  else // elements more complex than 0D
+  {
+    if ( !_ebbTree || _elementType != type )
+    {
+      if ( _ebbTree ) delete _ebbTree;
+      _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
+    }
+    TIDSortedElemSet suspectElems;
+    _ebbTree->getElementsNearPoint( point, suspectElems );
+    TIDSortedElemSet::iterator elem = suspectElems.begin();
+    for ( ; elem != suspectElems.end(); ++elem )
+      if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
+        foundElements.push_back( *elem );
+  }
+  return foundElements.size();
+}
+
+//================================================================================
+/*!
+ * \brief Classify the given point in the closed 2D mesh
+ */
+//================================================================================
+
+TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
+{
+  double tolerance = getTolerance();
+  if ( !_ebbTree || _elementType != SMDSAbs_Face )
+  {
+    if ( _ebbTree ) delete _ebbTree;
+    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
+  }
+  // Algo: analyse transition of a line starting at the point through mesh boundary;
+  // try three lines parallel to axis of the coordinate system and perform rough
+  // analysis. If solution is not clear perform thorough analysis.
+
+  const int nbAxes = 3;
+  gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
+  map< double, TInters >   paramOnLine2TInters[ nbAxes ];
+  list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
+  multimap< int, int > nbInt2Axis; // to find the simplest case
+  for ( int axis = 0; axis < nbAxes; ++axis )
+  {
+    gp_Ax1 lineAxis( point, axisDir[axis]);
+    gp_Lin line    ( lineAxis );
+
+    TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
+    _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
+
+    // Intersect faces with the line
+
+    map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
+    TIDSortedElemSet::iterator face = suspectFaces.begin();
+    for ( ; face != suspectFaces.end(); ++face )
+    {
+      // get face plane
+      gp_XYZ fNorm;
+      if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
+      gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
+
+      // perform intersection
+      IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
+      if ( !intersection.IsDone() )
+        continue;
+      if ( intersection.IsInQuadric() )
+      {
+        tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
+      }
+      else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
+      {
+        gp_Pnt intersectionPoint = intersection.Point(1);
+        if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
+          u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
       }
     }
-    // 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;
+    // Analyse intersections roughly
+
+    int nbInter = u2inters.size();
+    if ( nbInter == 0 )
+      return TopAbs_OUT; 
+
+    double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
+    if ( nbInter == 1 ) // not closed mesh
+      return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
+
+    if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
+      return TopAbs_ON;
+
+    if ( (f<0) == (l<0) )
+      return TopAbs_OUT;
+
+    int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
+    int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
+    if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
+      return TopAbs_IN;
+
+    nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
+
+    if ( _outerFacesFound ) break; // pass to thorough analysis
+
+  } // three attempts - loop on CS axes
+
+  // Analyse intersections thoroughly.
+  // We make two loops maximum, on the first one we only exclude touching intersections,
+  // on the second, if situation is still unclear, we gather and use information on
+  // position of faces (internal or outer). If faces position is already gathered,
+  // we make the second loop right away.
+
+  for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
+  {
+    multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
+    for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
+    {
+      int axis = nb_axis->second;
+      map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
+
+      gp_Ax1 lineAxis( point, axisDir[axis]);
+      gp_Lin line    ( lineAxis );
+
+      // add tangent intersections to u2inters
+      double param;
+      list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
+      for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
+        if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
+          u2inters.insert(make_pair( param, *tgtInt ));
+      tangentInters[ axis ].clear();
+
+      // Count intersections before and after the point excluding touching ones.
+      // If hasPositionInfo we count intersections of outer boundary only
+
+      int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
+      double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
+      map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
+      bool ok = ! u_int1->second._coincides;
+      while ( ok && u_int1 != u2inters.end() )
+      {
+        double u = u_int1->first;
+        bool touchingInt = false;
+        if ( ++u_int2 != u2inters.end() )
+        {
+          // skip intersections at the same point (if the line passes through edge or node)
+          int nbSamePnt = 0;
+          while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
+          {
+            ++nbSamePnt;
+            ++u_int2;
+          }
+
+          // skip tangent intersections
+          int nbTgt = 0;
+          const SMDS_MeshElement* prevFace = u_int1->second._face;
+          while ( ok && u_int2->second._coincides )
+          {
+            if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
+              ok = false;
+            else
+            {
+              nbTgt++;
+              u_int2++;
+              ok = ( u_int2 != u2inters.end() );
+            }
+          }
+          if ( !ok ) break;
+
+          // skip intersections at the same point after tangent intersections
+          if ( nbTgt > 0 )
+          {
+            double u2 = u_int2->first;
+            ++u_int2;
+            while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
+            {
+              ++nbSamePnt;
+              ++u_int2;
+            }
+          }
+          // decide if we skipped a touching intersection
+          if ( nbSamePnt + nbTgt > 0 )
+          {
+            double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
+            map< double, TInters >::iterator u_int = u_int1;
+            for ( ; u_int != u_int2; ++u_int )
+            {
+              if ( u_int->second._coincides ) continue;
+              double dot = u_int->second._faceNorm * line.Direction();
+              if ( dot > maxDot ) maxDot = dot;
+              if ( dot < minDot ) minDot = dot;
+            }
+            touchingInt = ( minDot*maxDot < 0 );
+          }
+        }
+        if ( !touchingInt )
+        {
+          if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
+          {
+            if ( u < 0 )
+              ++nbIntBeforePoint;
+            else
+              ++nbIntAfterPoint;
+          }
+          if ( u < f ) f = u;
+          if ( u > l ) l = u;
+        }
+
+        u_int1 = u_int2; // to next intersection
+
+      } // loop on intersections with one line
+
+      if ( ok )
+      {
+        if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
+          return TopAbs_ON;
+
+        if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
+          return TopAbs_OUT; 
+
+        if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
+          return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
+
+        if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
+          return TopAbs_IN;
+
+        if ( (f<0) == (l<0) )
+          return TopAbs_OUT;
+
+        if ( hasPositionInfo )
+          return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
       }
+    } // loop on intersections of the tree lines - thorough analysis
+
+    if ( !hasPositionInfo )
+    {
+      // gather info on faces position - is face in the outer boundary or not
+      map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
+      findOuterBoundary( u2inters.begin()->second._face );
     }
-    return closestNode;
-  }
-  /*!
-   * \brief Destructor
-   */
-  ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
-private:
-  SMESH_OctreeNode* myOctreeNode;
-};
+
+  } // two attempts - with and w/o faces position info in the mesh
+
+  return TopAbs_UNKNOWN;
+}
 
 //=======================================================================
 /*!
- * \brief Return SMESH_NodeSearcher
+ * \brief Return SMESH_ElementSearcher
  */
 //=======================================================================
 
-SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
+SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
 {
-  return new SMESH_NodeSearcherImpl( GetMeshDS() );
+  return new SMESH_ElementSearcherImpl( *GetMeshDS() );
+}
+
+//=======================================================================
+/*!
+ * \brief Return true if the point is IN or ON of the element
+ */
+//=======================================================================
+
+bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
+{
+  if ( element->GetType() == SMDSAbs_Volume)
+  {
+    return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
+  }
+
+  // get ordered nodes
+
+  vector< gp_XYZ > xyz;
+
+  SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
+  if ( element->IsQuadratic() )
+    if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
+      nodeIt = f->interlacedNodesElemIterator();
+    else if (const SMDS_QuadraticEdge*  e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
+      nodeIt = e->interlacedNodesElemIterator();
+
+  while ( nodeIt->more() )
+    xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
+
+  int i, nbNodes = element->NbNodes();
+
+  if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
+  {
+    // compute face normal
+    gp_Vec faceNorm(0,0,0);
+    xyz.push_back( xyz.front() );
+    for ( i = 0; i < nbNodes; ++i )
+    {
+      gp_Vec edge1( xyz[i+1], xyz[i]);
+      gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
+      faceNorm += edge1 ^ edge2;
+    }
+    double normSize = faceNorm.Magnitude();
+    if ( normSize <= tol )
+    {
+      // degenerated face: point is out if it is out of all face edges
+      for ( i = 0; i < nbNodes; ++i )
+      {
+        SMDS_MeshNode n1( xyz[i].X(),   xyz[i].Y(),   xyz[i].Z() );
+        SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
+        SMDS_MeshEdge edge( &n1, &n2 );
+        if ( !isOut( &edge, point, tol ))
+          return false;
+      }
+      return true;
+    }
+    faceNorm /= normSize;
+
+    // check if the point lays on face plane
+    gp_Vec n2p( xyz[0], point );
+    if ( fabs( n2p * faceNorm ) > tol )
+      return true; // not on face plane
+
+    // check if point is out of face boundary:
+    // define it by closest transition of a ray point->infinity through face boundary
+    // on the face plane.
+    // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
+    // to find intersections of the ray with the boundary.
+    gp_Vec ray = n2p;
+    gp_Vec plnNorm = ray ^ faceNorm;
+    normSize = plnNorm.Magnitude();
+    if ( normSize <= tol ) return false; // point coincides with the first node
+    plnNorm /= normSize;
+    // for each node of the face, compute its signed distance to the plane
+    vector<double> dist( nbNodes + 1);
+    for ( i = 0; i < nbNodes; ++i )
+    {
+      gp_Vec n2p( xyz[i], point );
+      dist[i] = n2p * plnNorm;
+    }
+    dist.back() = dist.front();
+    // find the closest intersection
+    int    iClosest = -1;
+    double rClosest, distClosest = 1e100;;
+    gp_Pnt pClosest;
+    for ( i = 0; i < nbNodes; ++i )
+    {
+      double r;
+      if ( fabs( dist[i]) < tol )
+        r = 0.;
+      else if ( fabs( dist[i+1]) < tol )
+        r = 1.;
+      else if ( dist[i] * dist[i+1] < 0 )
+        r = dist[i] / ( dist[i] - dist[i+1] );
+      else
+        continue; // no intersection
+      gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
+      gp_Vec p2int ( point, pInt);
+      if ( p2int * ray > -tol ) // right half-space
+      {
+        double intDist = p2int.SquareMagnitude();
+        if ( intDist < distClosest )
+        {
+          iClosest = i;
+          rClosest = r;
+          pClosest = pInt;
+          distClosest = intDist;
+        }
+      }
+    }
+    if ( iClosest < 0 )
+      return true; // no intesections - out
+
+    // analyse transition
+    gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
+    gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
+    gp_Vec p2int ( point, pClosest );
+    bool out = (edgeNorm * p2int) < -tol;
+    if ( rClosest > 0. && rClosest < 1. ) // not node intersection
+      return out;
+
+    // ray pass through a face node; analyze transition through an adjacent edge
+    gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
+    gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
+    gp_Vec edgeAdjacent( p1, p2 );
+    gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
+    bool out2 = (edgeNorm2 * p2int) < -tol;
+
+    bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
+    return covexCorner ? (out || out2) : (out && out2);
+  }
+  if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
+  {
+    // point is out of edge if it is NOT ON any straight part of edge
+    // (we consider quadratic edge as being composed of two straight parts)
+    for ( i = 1; i < nbNodes; ++i )
+    {
+      gp_Vec edge( xyz[i-1], xyz[i]);
+      gp_Vec n1p ( xyz[i-1], point);
+      double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
+      if ( dist > tol )
+        continue;
+      gp_Vec n2p( xyz[i], point );
+      if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
+        continue;
+      return false; // point is ON this part
+    }
+    return true;
+  }
+  // Node or 0D element -------------------------------------------------------------------------
+  {
+    gp_Vec n2p ( xyz[0], point );
+    return n2p.Magnitude() <= tol;
+  }
+  return true;
 }
 
 //=======================================================================
@@ -5317,7 +7061,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
       while ( invElemIt->more() ) {
         const SMDS_MeshElement* elem = invElemIt->next();
-          elems.insert(elem);
+        elems.insert(elem);
       }
     }
   }
@@ -5851,24 +7595,24 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 // ========================================================
 class SortableElement : public set <const SMDS_MeshElement*>
 {
- public:
+public:
 
   SortableElement( const SMDS_MeshElement* theElem )
-    {
-      myElem = theElem;
-      SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
-      while ( nodeIt->more() )
-        this->insert( nodeIt->next() );
-    }
+  {
+    myElem = theElem;
+    SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
+    while ( nodeIt->more() )
+      this->insert( nodeIt->next() );
+  }
 
   const SMDS_MeshElement* Get() const
-    { return myElem; }
+  { return myElem; }
 
   void Set(const SMDS_MeshElement* e) const
-    { myElem = e; }
+  { myElem = e; }
 
 
- private:
+private:
   mutable const SMDS_MeshElement* myElem;
 };
 
@@ -5878,7 +7622,7 @@ class SortableElement : public set <const SMDS_MeshElement*>
 //           Search among theElements or in the whole mesh if theElements is empty
 //=======================================================================
 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
-                                        TListOfListOfElementsID &      theGroupsOfElementsID)
+                                         TListOfListOfElementsID &      theGroupsOfElementsID)
 {
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
@@ -5976,7 +7720,7 @@ void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElemen
 void SMESH_MeshEditor::MergeEqualElements()
 {
   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
-                                                to merge equal elements in the whole mesh */
+                                                 to merge equal elements in the whole mesh */
   TListOfListOfElementsID aGroupsOfElementsID;
   FindEqualElements(aMeshElements, aGroupsOfElementsID);
   MergeElements(aGroupsOfElementsID);
@@ -5987,83 +7731,65 @@ void SMESH_MeshEditor::MergeEqualElements()
 //purpose  : Return a face having linked nodes n1 and n2 and which is
 //           - not in avoidSet,
 //           - in elemSet provided that !elemSet.empty()
+//           i1 and i2 optionally returns indices of n1 and n2
 //=======================================================================
 
 const SMDS_MeshElement*
-  SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
-                                  const SMDS_MeshNode*    n2,
-                                  const TIDSortedElemSet& elemSet,
-                                  const TIDSortedElemSet& avoidSet)
+SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
+                                const SMDS_MeshNode*    n2,
+                                const TIDSortedElemSet& elemSet,
+                                const TIDSortedElemSet& avoidSet,
+                                int*                    n1ind,
+                                int*                    n2ind)
 
 {
+  int i1, i2;
+  const SMDS_MeshElement* face = 0;
+
   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
-  while ( invElemIt->more() ) { // loop on inverse elements of n1
+  while ( invElemIt->more() && !face ) // loop on inverse faces of n1
+  {
     const SMDS_MeshElement* elem = invElemIt->next();
-    if (avoidSet.find( elem ) != avoidSet.end() )
+    if (avoidSet.count( elem ))
       continue;
-    if ( !elemSet.empty() && elemSet.find( elem ) == elemSet.end())
+    if ( !elemSet.empty() && !elemSet.count( elem ))
       continue;
-    // get face nodes and find index of n1
-    int i1, nbN = elem->NbNodes(), iNode = 0;
-    //const SMDS_MeshNode* faceNodes[ nbN ], *n;
-    vector<const SMDS_MeshNode*> faceNodes( nbN );
-    const SMDS_MeshNode* n;
-    SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
-    while ( nIt->more() ) {
-      faceNodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
-      if ( faceNodes[ iNode++ ] == n1 )
-        i1 = iNode - 1;
-    }
+    // index of n1
+    i1 = elem->GetNodeIndex( n1 );
     // find a n2 linked to n1
-    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;
-          }
+    int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
+    for ( int di = -1; di < 2 && !face; di += 2 )
+    {
+      i2 = (i1+di+nbN) % nbN;
+      if ( elem->GetNode( i2 ) == n2 )
+        face = elem;
+    }
+    if ( !face && elem->IsQuadratic())
+    {
+      // analysis for quadratic elements using all nodes
+      const SMDS_QuadraticFaceOfNodes* F =
+        static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
+      // use special nodes iterator
+      SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+      const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
+      for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
+      {
+        const SMDS_MeshNode* n = cast2Node( anIter->next() );
+        if ( n1 == prevN && n2 == n )
+        {
+          face = elem;
+        }
+        else if ( n2 == prevN && n1 == n )
+        {
+          face = elem; swap( i1, i2 );
         }
+        prevN = n;
       }
-    } // end analysis for quadratic elements
+    }
   }
-  return 0;
+  if ( n1ind ) *n1ind = i1;
+  if ( n2ind ) *n2ind = i2;
+  return face;
 }
 
 //=======================================================================
@@ -6107,7 +7833,7 @@ bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirst
 
   //vector<const SMDS_MeshNode*> nodes;
   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
-  set < const SMDS_MeshElement* > foundElems;
+  TIDSortedElemSet foundElems;
   bool needTheLast = ( theLastNode != 0 );
 
   while ( nStart != theLastNode ) {
@@ -6126,7 +7852,7 @@ bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirst
         int iNode = 0, nbNodes = e->NbNodes();
         //const SMDS_MeshNode* nodes[nbNodes+1];
         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
-        
+
         if(e->IsQuadratic()) {
           const SMDS_QuadraticFaceOfNodes* F =
             static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
@@ -6246,15 +7972,15 @@ bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
 //=======================================================================
 
 SMESH_MeshEditor::Sew_Error
-  SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
-                                   const SMDS_MeshNode* theBordSecondNode,
-                                   const SMDS_MeshNode* theBordLastNode,
-                                   const SMDS_MeshNode* theSideFirstNode,
-                                   const SMDS_MeshNode* theSideSecondNode,
-                                   const SMDS_MeshNode* theSideThirdNode,
-                                   const bool           theSideIsFreeBorder,
-                                   const bool           toCreatePolygons,
-                                   const bool           toCreatePolyedrs)
+SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
+                                 const SMDS_MeshNode* theBordSecondNode,
+                                 const SMDS_MeshNode* theBordLastNode,
+                                 const SMDS_MeshNode* theSideFirstNode,
+                                 const SMDS_MeshNode* theSideSecondNode,
+                                 const SMDS_MeshNode* theSideThirdNode,
+                                 const bool           theSideIsFreeBorder,
+                                 const bool           toCreatePolygons,
+                                 const bool           toCreatePolyedrs)
 {
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
@@ -6508,7 +8234,7 @@ SMESH_MeshEditor::Sew_Error
 
   TListOfListOfNodes nodeGroupsToMerge;
   if ( nbNodes[0] == nbNodes[1] ||
-      ( theSideIsFreeBorder && !theSideThirdNode)) {
+       ( theSideIsFreeBorder && !theSideThirdNode)) {
 
     // all nodes are to be merged
 
@@ -7159,44 +8885,47 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
     switch( aType )
     {
     case SMDSAbs_Edge :
-    {
-      NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
-      break;
-    }
+      {
+        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;
+        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;
       }
-      break;
-    }
     case SMDSAbs_Volume :
-    {
-      switch(nbNodes)
       {
-      case 4:
-       NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
-       break;
-      case 6:
-       NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
-       break;
-      case 8:
-       NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
-                                      aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
-       break;
-      default:
-       continue;
+        switch(nbNodes)
+        {
+        case 4:
+          NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
+          break;
+        case 5:
+          NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
+          break;
+        case 6:
+          NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
+          break;
+        case 8:
+          NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
+                                        aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
+          break;
+        default:
+          continue;
+        }
+        break;
       }
-      break;
-    }
     default :
       continue;
     }
@@ -7229,7 +8958,6 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
         SMESH_subMesh* sm = smIt->next();
         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
           aHelper.SetSubShape( sm->GetSubShape() );
-          if ( !theForce3d) aHelper.SetCheckNodePosition(true);
           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
         }
       }
@@ -7245,11 +8973,11 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
       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);
+        int id = edge->GetID();
+        const SMDS_MeshNode* n1 = edge->GetNode(0);
+        const SMDS_MeshNode* n2 = edge->GetNode(1);
 
-       meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
+        meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
 
         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
@@ -7267,7 +8995,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
 
       for(int i = 0; i < nbNodes; i++)
       {
-       aNds[i] = face->GetNode(i);
+        aNds[i] = face->GetNode(i);
       }
 
       meshDS->RemoveFreeElement(face, smDS, notFromGroups);
@@ -7276,13 +9004,13 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
       switch(nbNodes)
       {
       case 3:
-       NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
-       break;
+        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;
+        NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
+        break;
       default:
-       continue;
+        continue;
       }
       ReplaceElemInGroups( face, NewFace, GetMeshDS());
     }
@@ -7298,7 +9026,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
 
       for(int i = 0; i < nbNodes; i++)
       {
-       aNds[i] = volume->GetNode(i);
+        aNds[i] = volume->GetNode(i);
       }
 
       meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
@@ -7307,19 +9035,23 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
       switch(nbNodes)
       {
       case 4:
-       NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
+        NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
                                       aNds[3], id, theForce3d );
-       break;
+        break;
+      case 5:
+        NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
+                                      aNds[3], aNds[4], id, theForce3d);
+        break;
       case 6:
-       NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
+        NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
                                       aNds[3], aNds[4], aNds[5], id, theForce3d);
-       break;
+        break;
       case 8:
-       NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
+        NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
                                       aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
-       break;
+        break;
       default:
-       continue;
+        continue;
       }
       ReplaceElemInGroups(volume, NewVolume, meshDS);
     }
@@ -7359,12 +9091,12 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
 
       for(int i = 0; i < nbNodes; i++)
       {
-       const SMDS_MeshNode* n = elem->GetNode(i);
+        const SMDS_MeshNode* n = elem->GetNode(i);
 
-       if( elem->IsMediumNode( n ) )
+        if( elem->IsMediumNode( n ) )
           mediumNodes.push_back( n );
-       else
-         aNds.push_back( n );
+        else
+          aNds.push_back( n );
       }
       if( aNds.empty() ) continue;
       SMDSAbs_ElementType aType = elem->GetType();
@@ -7375,7 +9107,7 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
       SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
       ReplaceElemInGroups(elem, NewElem, meshDS);
       if( theSm && NewElem )
-       theSm->AddElement( NewElem );
+        theSm->AddElement( NewElem );
 
       // remove medium nodes
       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
@@ -7387,7 +9119,7 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
                                     ( n->GetPosition()->GetShapeId() ));
           else
             meshDS->RemoveFreeNode( n, theSm );
-       }
+        }
       }
     }
   }
@@ -7413,7 +9145,7 @@ bool  SMESH_MeshEditor::ConvertFromQuadratic()
       }
     }
   }
-  
+
   int totalNbElems =
     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
@@ -7431,12 +9163,12 @@ bool  SMESH_MeshEditor::ConvertFromQuadratic()
 //=======================================================================
 
 SMESH_MeshEditor::Sew_Error
-  SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
-                                     TIDSortedElemSet&    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();
@@ -7675,40 +9407,40 @@ SMESH_MeshEditor::Sew_Error
           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
           faceSet->insert( aFreeFace );
           // complete a node set with nodes of a found free face
-//           for ( iNode = 0; iNode < ; iNode++ )
-//             nodeSet->insert( fNodes[ iNode ] );
+          //           for ( iNode = 0; iNode < ; iNode++ )
+          //             nodeSet->insert( fNodes[ iNode ] );
         }
 
       } // loop on volumes of a side
 
-//       // complete a set of faces if new nodes in a nodeSet appeared
-//       // ----------------------------------------------------------
-//       if ( nodeSetSize != nodeSet->size() ) {
-//         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
-//           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() ) {
-//               // check if all nodes are in nodeSet and
-//               // complete setOfFaceNodeSet if they are
-//               set <const SMDS_MeshNode*> faceNodeSet;
-//               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
-//               bool allInSet = true;
-//               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
-//                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
-//                 if ( nodeSet->find( n ) == nodeSet->end() )
-//                   allInSet = false;
-//                 else
-//                   faceNodeSet.insert( n );
-//               }
-//               if ( allInSet ) {
-//                 faceSet->insert( f );
-//                 setOfFaceNodeSet.insert( faceNodeSet );
-//               }
-//             }
-//           }
-//         }
-//       }
+      //       // complete a set of faces if new nodes in a nodeSet appeared
+      //       // ----------------------------------------------------------
+      //       if ( nodeSetSize != nodeSet->size() ) {
+      //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
+      //           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() ) {
+      //               // check if all nodes are in nodeSet and
+      //               // complete setOfFaceNodeSet if they are
+      //               set <const SMDS_MeshNode*> faceNodeSet;
+      //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
+      //               bool allInSet = true;
+      //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
+      //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
+      //                 if ( nodeSet->find( n ) == nodeSet->end() )
+      //                   allInSet = false;
+      //                 else
+      //                   faceNodeSet.insert( n );
+      //               }
+      //               if ( allInSet ) {
+      //                 faceSet->insert( f );
+      //                 setOfFaceNodeSet.insert( faceNodeSet );
+      //               }
+      //             }
+      //           }
+      //         }
+      //       }
     } // Create temporary faces, if there are volumes given
   } // loop on sides
 
@@ -7814,10 +9546,10 @@ SMESH_MeshEditor::Sew_Error
                   nbl++;
                   if(iSide==0)
                     notLinkNodes1[nbl] = n;
-                    //notLinkNodes1.push_back(n);
+                  //notLinkNodes1.push_back(n);
                   else
                     notLinkNodes2[nbl] = n;
-                    //notLinkNodes2.push_back(n);
+                  //notLinkNodes2.push_back(n);
                 }
                 //faceNodes[ iSide ][ iNode++ ] = n;
                 if(iSide==0) {
@@ -7898,7 +9630,7 @@ SMESH_MeshEditor::Sew_Error
         //nReplaceMap.insert( TNodeNodeMap::value_type
         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
         nReplaceMap.insert( TNodeNodeMap::value_type
-                           ( notLinkNodes1[0], notLinkNodes2[0] ));
+                            ( notLinkNodes1[0], notLinkNodes2[0] ));
       }
       else {
         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
@@ -7919,7 +9651,7 @@ SMESH_MeshEditor::Sew_Error
           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
           for(int nn=0; nn<nbNodes-2; nn++) {
             nReplaceMap.insert( TNodeNodeMap::value_type
-                             ( notLinkNodes1[nn], notLinkNodes2[nn] ));
+                                ( notLinkNodes1[nn], notLinkNodes2[nn] ));
           }
         }
         else {
@@ -7929,7 +9661,7 @@ SMESH_MeshEditor::Sew_Error
           //                   ( 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] ));
+                                ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
           }
         }
       }
@@ -7959,10 +9691,10 @@ SMESH_MeshEditor::Sew_Error
   } // loop on link lists
 
   if ( aResult == SEW_OK &&
-      ( linkIt[0] != linkList[0].end() ||
-       !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
+       ( linkIt[0] != linkList[0].end() ||
+         !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
-            " " << (faceSetPtr[1]->empty()));
+             " " << (faceSetPtr[1]->empty()));
     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
   }
 
@@ -8017,17 +9749,17 @@ SMESH_MeshEditor::Sew_Error
 }
 
 //================================================================================
-  /*!
  * \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
  */
+/*!
+ * \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
+ */
 //================================================================================
 
 #ifdef _DEBUG_
@@ -8144,8 +9876,8 @@ SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
       }
 #ifdef DEBUG_MATCHING_NODES
       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
-             << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
-            << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
+                << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
+                << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
 #endif
       int nbN = nbNodes[0];
       {
@@ -8176,7 +9908,7 @@ SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
         {
 #ifdef DEBUG_MATCHING_NODES
           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
-         << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
+                    << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
 #endif
           linkList[0].push_back ( NLink( n1, n2 ));
           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
@@ -8189,15 +9921,18 @@ SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
   return SEW_OK;
 }
 
+//================================================================================
 /*!
   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
   \param theElems - the list of elements (edges or faces) to be replicated
-        The nodes for duplication could be found from these elements
+  The nodes for duplication could be found from these elements
   \param theNodesNot - list of nodes to NOT replicate
   \param theAffectedElems - the list of elements (cells and edges) to which the 
-        replicated nodes should be associated to.
+  replicated nodes should be associated to.
   \return TRUE if operation has been completed successfully, FALSE otherwise
 */
+//================================================================================
+
 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
                                     const TIDSortedElemSet& theNodesNot,
                                     const TIDSortedElemSet& theAffectedElems )
@@ -8221,6 +9956,7 @@ bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
   return res;
 }
 
+//================================================================================
 /*!
   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
   \param theMeshDS - mesh instance
@@ -8230,6 +9966,8 @@ bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
   \param theIsDoubleElem - flag os to replicate element or modify
   \return TRUE if operation has been completed successfully, FALSE otherwise
 */
+//================================================================================
+
 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
                                     const TIDSortedElemSet& theElems,
                                     const TIDSortedElemSet& theNodesNot,
@@ -8239,7 +9977,7 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
 {
   // iterate on through element and duplicate them (by nodes duplication)
   bool res = false;
-  const TIDSortedElemSet::iterator elemItr = theElems.begin();
+  TIDSortedElemSet::const_iterator elemItr = theElems.begin();
   for ( ;  elemItr != theElems.end(); ++elemItr )
   {
     const SMDS_MeshElement* anElem = *elemItr;
@@ -8253,7 +9991,7 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
     int ind = 0;
     while ( anIter->more() ) 
     { 
-      
+
       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
       SMDS_MeshNode* aNewNode = aCurrNode;
       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
@@ -8265,71 +10003,209 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
         theNodeNodeMap[ aCurrNode ] = aNewNode;
         myLastCreatedNodes.Append( aNewNode );
       }
-      isDuplicate |= (aCurrNode == aNewNode);
+      isDuplicate |= (aCurrNode != aNewNode);
       newNodes[ ind++ ] = aNewNode;
     }
     if ( !isDuplicate )
       continue;
-  
+
     if ( theIsDoubleElem )
       myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
     else
       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
-          
+
     res = true;
   }
   return res;
 }
 
+//================================================================================
 /*!
-  \brief Check if element located inside shape
-  \return TRUE if IN or ON shape, FALSE otherwise
+  \brief Creates a hole in a mesh by doubling the nodes of some particular elements
+  \param theNodes - identifiers of nodes to be doubled
+  \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
+         nodes. If list of element identifiers is empty then nodes are doubled but 
+         they not assigned to elements
+  \return TRUE if operation has been completed successfully, FALSE otherwise
 */
+//================================================================================
 
-static bool isInside(const SMDS_MeshElement* theElem,
-                     BRepClass3d_SolidClassifier& theBsc3d,
-                     const double theTol)
+bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
+                                    const std::list< int >& theListOfModifiedElems )
 {
-  gp_XYZ centerXYZ (0, 0, 0);
-  SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
-  while (aNodeItr->more())
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
+  if ( theListOfNodes.size() == 0 )
+    return false;
+
+  SMESHDS_Mesh* aMeshDS = GetMeshDS();
+  if ( !aMeshDS )
+    return false;
+
+  // iterate through nodes and duplicate them
+
+  std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
+
+  std::list< int >::const_iterator aNodeIter;
+  for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
+  {
+    int aCurr = *aNodeIter;
+    SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
+    if ( !aNode )
+      continue;
+
+    // duplicate node
+
+    const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
+    if ( aNewNode )
+    {
+      anOldNodeToNewNode[ aNode ] = aNewNode;
+      myLastCreatedNodes.Append( aNewNode );
+    }
+  }
+
+  // Create map of new nodes for modified elements
+
+  std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
+
+  std::list< int >::const_iterator anElemIter;
+  for ( anElemIter = theListOfModifiedElems.begin(); 
+        anElemIter != theListOfModifiedElems.end(); ++anElemIter )
+  {
+    int aCurr = *anElemIter;
+    SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
+    if ( !anElem )
+      continue;
+
+    vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
+
+    SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
+    int ind = 0;
+    while ( anIter->more() ) 
+    { 
+      SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
+      if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
+      {
+        const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
+        aNodeArr[ ind++ ] = aNewNode;
+      }
+      else
+        aNodeArr[ ind++ ] = aCurrNode;
+    }
+    anElemToNodes[ anElem ] = aNodeArr;
+  }
+
+  // Change nodes of elements  
+
+  std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
+    anElemToNodesIter = anElemToNodes.begin();
+  for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
+  {
+    const SMDS_MeshElement* anElem = anElemToNodesIter->first;
+    vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
+    if ( anElem )
+      aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
+  }
+
+  return true;
+}
+
+namespace {
+
+  //================================================================================
+  /*!
+  \brief Check if element located inside shape
+  \return TRUE if IN or ON shape, FALSE otherwise
+  */
+  //================================================================================
+
+  template<class Classifier>
+  bool isInside(const SMDS_MeshElement* theElem,
+                Classifier&             theClassifier,
+                const double            theTol)
   {
-    SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
-    centerXYZ += gp_XYZ(aNode->X(), aNode->Y(), aNode->Z());
+    gp_XYZ centerXYZ (0, 0, 0);
+    SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
+    while (aNodeItr->more())
+      centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
+
+    gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
+    theClassifier.Perform(aPnt, theTol);
+    TopAbs_State aState = theClassifier.State();
+    return (aState == TopAbs_IN || aState == TopAbs_ON );
   }
-  gp_Pnt aPnt(centerXYZ);
-  theBsc3d.Perform(aPnt, theTol);
-  TopAbs_State aState = theBsc3d.State();
-  return (aState == TopAbs_IN || aState == TopAbs_ON );
+
+  //================================================================================
+  /*!
+   * \brief Classifier of the 3D point on the TopoDS_Face
+   *        with interaface suitable for isInside()
+   */
+  //================================================================================
+
+  struct _FaceClassifier
+  {
+    Extrema_ExtPS       _extremum;
+    BRepAdaptor_Surface _surface;
+    TopAbs_State        _state;
+
+    _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
+    {
+      _extremum.Initialize( _surface,
+                            _surface.FirstUParameter(), _surface.LastUParameter(),
+                            _surface.FirstVParameter(), _surface.LastVParameter(),
+                            _surface.Tolerance(), _surface.Tolerance() );
+    }
+    void Perform(const gp_Pnt& aPnt, double theTol)
+    {
+      _state = TopAbs_OUT;
+      _extremum.Perform(aPnt);
+      if ( _extremum.IsDone() )
+        for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
+          _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
+    }
+    TopAbs_State State() const
+    {
+      return _state;
+    }
+  };
 }
 
+//================================================================================
 /*!
   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
   \param theElems - group of of elements (edges or faces) to be replicated
-  \param theNodesNot - group of nodes not to replicated
+  \param theNodesNot - group of nodes not to replicate
   \param theShape - shape to detect affected elements (element which geometric center
-         located on or inside shape).
-         The replicated nodes should be associated to affected elements.
+  located on or inside shape).
+  The replicated nodes should be associated to affected elements.
   \return TRUE if operation has been completed successfully, FALSE otherwise
 */
+//================================================================================
 
 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
                                             const TIDSortedElemSet& theNodesNot,
                                             const TopoDS_Shape&     theShape )
 {
-  SMESHDS_Mesh* aMesh = GetMeshDS();
-  if (!aMesh)
-    return false;
   if ( theShape.IsNull() )
     return false;
 
   const double aTol = Precision::Confusion();
-  BRepClass3d_SolidClassifier bsc3d(theShape);
-  bsc3d.PerformInfinitePoint(aTol);
+  auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
+  auto_ptr<_FaceClassifier>              aFaceClassifier;
+  if ( theShape.ShapeType() == TopAbs_SOLID )
+  {
+    bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
+    bsc3d->PerformInfinitePoint(aTol);
+  }
+  else if (theShape.ShapeType() == TopAbs_FACE )
+  {
+    aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
+  }
 
   // iterates on indicated elements and get elements by back references from their nodes
   TIDSortedElemSet anAffected;
-  const TIDSortedElemSet::iterator elemItr = theElems.begin();
+  TIDSortedElemSet::const_iterator elemItr = theElems.begin();
   for ( ;  elemItr != theElems.end(); ++elemItr )
   {
     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
@@ -8339,18 +10215,71 @@ bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
     while ( nodeItr->more() )
     {
-      const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(nodeItr->next());
+      const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
         continue;
       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
       while ( backElemItr->more() )
       {
-        SMDS_MeshElement* curElem = (SMDS_MeshElement*)backElemItr->next();
+        const SMDS_MeshElement* curElem = backElemItr->next();
         if ( curElem && theElems.find(curElem) == theElems.end() &&
-             isInside( curElem, bsc3d, aTol ) )
+             ( bsc3d.get() ?
+               isInside( curElem, *bsc3d, aTol ) :
+               isInside( curElem, *aFaceClassifier, aTol )))
           anAffected.insert( curElem );
       }
     }
   }
   return DoubleNodes( theElems, theNodesNot, anAffected );
 }
+
+//================================================================================
+/*!
+ * \brief Generated skin mesh (containing 2D cells) from 3D mesh
+ * The created 2D mesh elements based on nodes of free faces of boundary volumes
+ * \return TRUE if operation has been completed successfully, FALSE otherwise
+ */
+//================================================================================
+
+bool SMESH_MeshEditor::Make2DMeshFrom3D()
+{
+  // iterates on volume elements and detect all free faces on them
+  SMESHDS_Mesh* aMesh = GetMeshDS();
+  if (!aMesh)
+    return false;
+  //bool res = false;
+  int nbFree = 0, nbExisted = 0, nbCreated = 0;
+  SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
+  while(vIt->more())
+  {
+    const SMDS_MeshVolume* volume = vIt->next();
+    SMDS_VolumeTool vTool( volume );
+    vTool.SetExternalNormal();
+    const bool isPoly = volume->IsPoly();
+    const bool isQuad = volume->IsQuadratic();
+    for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
+    {
+      if (!vTool.IsFreeFace(iface))
+        continue;
+      nbFree++;
+      vector<const SMDS_MeshNode *> nodes;
+      int nbFaceNodes = vTool.NbFaceNodes(iface);
+      const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
+      int inode = 0;
+      for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
+        nodes.push_back(faceNodes[inode]);
+      if (isQuad)
+        for ( inode = 1; inode < nbFaceNodes; inode += 2)
+          nodes.push_back(faceNodes[inode]);
+
+      // add new face based on volume nodes
+      if (aMesh->FindFace( nodes ) ) {
+        nbExisted++;
+        continue; // face already exsist
+      }
+      myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
+      nbCreated++;
+    }
+  }
+  return ( nbFree==(nbExisted+nbCreated) );
+}