Salome HOME
Update copyrights
[modules/smesh.git] / src / SMESH_I / SMESH_MeshEditor_i.cxx
index 87e88611289bc893010542658742e0552164cc85..ba435e4aac7fde3eeb4d8931fa1d83b43341e0f6 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2019  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -6,7 +6,7 @@
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 // License as published by the Free Software Foundation; either
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 // License as published by the Free Software Foundation; either
-// version 2.1 of the License.
+// version 2.1 of the License, or (at your option) any later version.
 //
 // This library is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 //
 // This library is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 //  Author : Nicolas REJNERI
 //  Module : SMESH
 
 //  Author : Nicolas REJNERI
 //  Module : SMESH
 
-#ifdef WNT
+#ifdef WIN32
 #define NOMINMAX
 #endif
 
 #define NOMINMAX
 #endif
 
+// A macro used in SMESH_TryCatch.hxx,
+// it re-raises a CORBA SALOME exception thrown by SMESH_MeshEditor_i and caught by SMESH_CATCH
+#define SMY_OWN_CATCH \
+  catch ( SALOME::SALOME_Exception & e ) { throw e; }
+
 #include "SMESH_MeshEditor_i.hxx"
 
 #include "SMDS_EdgePosition.hxx"
 #include "SMESH_MeshEditor_i.hxx"
 
 #include "SMDS_EdgePosition.hxx"
@@ -37,7 +42,6 @@
 #include "SMDS_Mesh0DElement.hxx"
 #include "SMDS_MeshFace.hxx"
 #include "SMDS_MeshVolume.hxx"
 #include "SMDS_Mesh0DElement.hxx"
 #include "SMDS_MeshFace.hxx"
 #include "SMDS_MeshVolume.hxx"
-#include "SMDS_PolyhedralVolumeOfNodes.hxx"
 #include "SMDS_SetIterator.hxx"
 #include "SMDS_VolumeTool.hxx"
 #include "SMESHDS_Group.hxx"
 #include "SMDS_SetIterator.hxx"
 #include "SMDS_VolumeTool.hxx"
 #include "SMESHDS_Group.hxx"
@@ -47,6 +51,7 @@
 #include "SMESH_Gen_i.hxx"
 #include "SMESH_Group.hxx"
 #include "SMESH_Group_i.hxx"
 #include "SMESH_Gen_i.hxx"
 #include "SMESH_Group.hxx"
 #include "SMESH_Group_i.hxx"
+#include "SMESH_MeshAlgos.hxx"
 #include "SMESH_MeshPartDS.hxx"
 #include "SMESH_MesherHelper.hxx"
 #include "SMESH_PythonDump.hxx"
 #include "SMESH_MeshPartDS.hxx"
 #include "SMESH_MesherHelper.hxx"
 #include "SMESH_PythonDump.hxx"
@@ -57,6 +62,7 @@
 #include <Utils_ExceptHandlers.hxx>
 #include <Utils_CorbaException.hxx>
 #include <SALOMEDS_wrap.hxx>
 #include <Utils_ExceptHandlers.hxx>
 #include <Utils_CorbaException.hxx>
 #include <SALOMEDS_wrap.hxx>
+#include <SALOME_GenericObj_i.hh>
 
 #include <BRepAdaptor_Surface.hxx>
 #include <BRep_Tool.hxx>
 
 #include <BRepAdaptor_Surface.hxx>
 #include <BRep_Tool.hxx>
 #include <gp_Ax2.hxx>
 #include <gp_Vec.hxx>
 
 #include <gp_Ax2.hxx>
 #include <gp_Vec.hxx>
 
-#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
-#define NO_CAS_CATCH
-#endif
-
 #include <Standard_Failure.hxx>
 #include <Standard_Failure.hxx>
-
-#ifdef NO_CAS_CATCH
 #include <Standard_ErrorHandler.hxx>
 #include <Standard_ErrorHandler.hxx>
-#endif
 
 #include <sstream>
 #include <limits>
 
 #include <sstream>
 #include <limits>
@@ -102,12 +101,10 @@ namespace MeshEditor_I {
     SMDSAbs_ElementType myPreviewType; // type to show
     //!< Constructor
     TPreviewMesh(SMDSAbs_ElementType previewElements = SMDSAbs_All) {
     SMDSAbs_ElementType myPreviewType; // type to show
     //!< Constructor
     TPreviewMesh(SMDSAbs_ElementType previewElements = SMDSAbs_All) {
-      _isShapeToMesh = (_id =_studyId = 0);
+      _isShapeToMesh = (_id = 0);
       _myMeshDS  = new SMESHDS_Mesh( _id, true );
       myPreviewType = previewElements;
     }
       _myMeshDS  = new SMESHDS_Mesh( _id, true );
       myPreviewType = previewElements;
     }
-    //!< Destructor
-    virtual ~TPreviewMesh() { delete _myMeshDS; _myMeshDS = 0; }
     //!< Copy a set of elements
     void Copy(const TIDSortedElemSet & theElements,
               TIDSortedElemSet&        theCopyElements,
     //!< Copy a set of elements
     void Copy(const TIDSortedElemSet & theElements,
               TIDSortedElemSet&        theCopyElements,
@@ -148,20 +145,11 @@ namespace MeshEditor_I {
       }
 
       // creates a corresponding element on copied nodes
       }
 
       // creates a corresponding element on copied nodes
-      SMDS_MeshElement* anElemCopy = 0;
-      if ( anElem->IsPoly() && anElem->GetType() == SMDSAbs_Volume )
-      {
-        const SMDS_VtkVolume* ph =
-          dynamic_cast<const SMDS_VtkVolume*> (anElem);
-        if ( ph )
-          anElemCopy = _myMeshDS->AddPolyhedralVolumeWithID
-            (anElemNodesID, ph->GetQuantities(),anElem->GetID());
-      }
-      else {
-        anElemCopy = ::SMESH_MeshEditor(this).AddElement( anElemNodesID,
-                                                          anElem->GetType(),
-                                                          anElem->IsPoly() );
-      }
+      ::SMESH_MeshEditor::ElemFeatures elemType;
+      elemType.Init( anElem, /*basicOnly=*/false );
+      elemType.SetID( anElem->GetID() );
+      SMDS_MeshElement* anElemCopy =
+        ::SMESH_MeshEditor(this).AddElement( anElemNodesID, elemType );
       return anElemCopy;
     }
     //!< Copy a node
       return anElemCopy;
     }
     //!< Copy a node
@@ -170,6 +158,19 @@ namespace MeshEditor_I {
       return _myMeshDS->AddNodeWithID(anElemNode->X(), anElemNode->Y(), anElemNode->Z(),
                                       anElemNode->GetID());
     }
       return _myMeshDS->AddNodeWithID(anElemNode->X(), anElemNode->Y(), anElemNode->Z(),
                                       anElemNode->GetID());
     }
+    void RemoveAll()
+    {
+      GetMeshDS()->ClearMesh();
+    }
+    void Remove( SMDSAbs_ElementType type )
+    {
+      Remove( GetMeshDS()->elementsIterator( type ));
+    }
+    void Remove( SMDS_ElemIteratorPtr eIt )
+    {
+      while ( eIt->more() )
+        GetMeshDS()->RemoveFreeElement( eIt->next(), /*sm=*/0, /*fromGroups=*/false );
+    }
   };// struct TPreviewMesh
 
   static SMESH_NodeSearcher *    theNodeSearcher    = 0;
   };// struct TPreviewMesh
 
   static SMESH_NodeSearcher *    theNodeSearcher    = 0;
@@ -177,7 +178,7 @@ namespace MeshEditor_I {
 
   //=============================================================================
   /*!
 
   //=============================================================================
   /*!
-   * \brief Deleter of theNodeSearcher at any compute event occured
+   * \brief Deleter of theNodeSearcher and theElementSearcher at any compute event occurred
    */
   //=============================================================================
 
    */
   //=============================================================================
 
@@ -216,22 +217,22 @@ namespace MeshEditor_I {
         }
         myMesh = mesh;
         myMeshPartIOR = meshPartIOR;
         }
         myMesh = mesh;
         myMeshPartIOR = meshPartIOR;
-        if ( SMESH_subMesh* myMainSubMesh = mesh->GetSubMeshContaining(1) ) {
-          const TDependsOnMap & subMeshes = myMainSubMesh->DependsOn();
-          TDependsOnMap::const_iterator sm;
-          for (sm = subMeshes.begin(); sm != subMeshes.end(); sm++)
-            sm->second->SetEventListener( this, 0, sm->second );
+        SMESH_subMesh* sm = mesh->GetSubMesh( mesh->GetShapeToMesh() );
+        SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator( /*includeSelf=*/true );
+        while ( smIt->more() )
+        {
+          sm = smIt->next();
+          sm->SetEventListener( this, 0, sm );
         }
       }
     }
     //!<  delete self from all submeshes
     void Unset(SMESH_Mesh* mesh)
     {
         }
       }
     }
     //!<  delete self from all submeshes
     void Unset(SMESH_Mesh* mesh)
     {
-      if ( SMESH_subMesh* myMainSubMesh = mesh->GetSubMeshContaining(1) ) {
-        const TDependsOnMap & subMeshes = myMainSubMesh->DependsOn();
-        TDependsOnMap::const_iterator sm;
-        for (sm = subMeshes.begin(); sm != subMeshes.end(); sm++)
-          sm->second->DeleteEventListener( this );
+      if ( SMESH_subMesh* sm = mesh->GetSubMeshContaining(1) ) {
+        SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator( /*includeSelf=*/true );
+        while ( smIt->more() )
+          smIt->next()->DeleteEventListener( this );
       }
       myMesh = 0;
     }
       }
       myMesh = 0;
     }
@@ -266,85 +267,66 @@ namespace MeshEditor_I {
   void arrayToSet(const SMESH::long_array & IDs,
                   const SMESHDS_Mesh*       aMesh,
                   TIDSortedElemSet&         aMap,
   void arrayToSet(const SMESH::long_array & IDs,
                   const SMESHDS_Mesh*       aMesh,
                   TIDSortedElemSet&         aMap,
-                  const SMDSAbs_ElementType aType = SMDSAbs_All )
-  {
-    for (int i=0; i<IDs.length(); i++) {
-      CORBA::Long ind = IDs[i];
-      const SMDS_MeshElement * elem =
-        (aType == SMDSAbs_Node ? aMesh->FindNode(ind) : aMesh->FindElement(ind));
-      if ( elem && ( aType == SMDSAbs_All || elem->GetType() == aType ))
-        aMap.insert( aMap.end(), elem );
-    }
-  }
-  //================================================================================
-  /*!
-   * \brief Retrieve elements of given type from SMESH_IDSource
-   */
-  //================================================================================
-
-  bool idSourceToSet(SMESH::SMESH_IDSource_ptr  theIDSource,
-                     const SMESHDS_Mesh*        theMeshDS,
-                     TIDSortedElemSet&          theElemSet,
-                     const SMDSAbs_ElementType  theType,
-                     const bool                 emptyIfIsMesh=false)
-
+                  const SMDSAbs_ElementType aType = SMDSAbs_All,
+                  SMDS_MeshElement::Filter* aFilter = NULL)
   {
   {
-    if ( CORBA::is_nil( theIDSource ) )
-      return false;
-    if ( emptyIfIsMesh && SMESH::DownCast<SMESH_Mesh_i*>( theIDSource ))
-      return true;
+    SMDS_MeshElement::NonNullFilter filter1;
+    SMDS_MeshElement::TypeFilter    filter2( aType );
 
 
-    SMESH::long_array_var anIDs = theIDSource->GetIDs();
-    if ( anIDs->length() == 0 )
-      return false;
-    SMESH::array_of_ElementType_var types = theIDSource->GetTypes();
-    if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
-    {
-      if ( theType == SMDSAbs_All || theType == SMDSAbs_Node )
-        arrayToSet( anIDs, theMeshDS, theElemSet, SMDSAbs_Node );
-      else
-        return false;
-    }
+    if ( aFilter == NULL )
+      aFilter = ( aType == SMDSAbs_All ) ? (SMDS_MeshElement::Filter*) &filter1 : (SMDS_MeshElement::Filter*) &filter2;
+    
+    SMDS_MeshElement::Filter & filter = *aFilter;
+
+    if ( aType == SMDSAbs_Node )
+      for ( CORBA::ULong i = 0; i < IDs.length(); i++ ) {
+        const SMDS_MeshElement * elem = aMesh->FindNode( IDs[i] );
+        if ( filter( elem ))
+          aMap.insert( aMap.end(), elem );
+      }
     else
     else
-    {
-      arrayToSet( anIDs, theMeshDS, theElemSet, theType);
-      return bool(anIDs->length()) == bool(theElemSet.size());
-    }
-    return true;
+      for ( CORBA::ULong i = 0; i<IDs.length(); i++) {
+        const SMDS_MeshElement * elem = aMesh->FindElement( IDs[i] );
+        if ( filter( elem ))
+          aMap.insert( aMap.end(), elem );
+      }
   }
   }
+
   //================================================================================
   /*!
    * \brief Retrieve nodes from SMESH_IDSource
    */
   //================================================================================
 
   //================================================================================
   /*!
    * \brief Retrieve nodes from SMESH_IDSource
    */
   //================================================================================
 
-  void idSourceToNodeSet(SMESH::SMESH_IDSource_ptr  theObject,
-                         const SMESHDS_Mesh*        theMeshDS,
-                         TIDSortedNodeSet&          theNodeSet)
+  void idSourceToNodeSet(SMESH::SMESH_IDSource_ptr theObject,
+                         const SMESHDS_Mesh*       theMeshDS,
+                         TIDSortedNodeSet&         theNodeSet)
 
   {
     if ( CORBA::is_nil( theObject ) )
       return;
 
   {
     if ( CORBA::is_nil( theObject ) )
       return;
-    SMESH::array_of_ElementType_var types = theObject->GetTypes();
-    SMESH::long_array_var     aElementsId = theObject->GetIDs();
-    if ( types->length() == 1 && types[0] == SMESH::NODE)
+    if ( SMESH::DownCast<SMESH_Mesh_i*>( theObject ))
     {
     {
-      for(int i = 0; i < aElementsId->length(); i++)
-        if ( const SMDS_MeshNode * n = theMeshDS->FindNode( aElementsId[i] ))
-          theNodeSet.insert( theNodeSet.end(), n);
-    }
-    else if ( SMESH::DownCast<SMESH_Mesh_i*>( theObject ))
-    {
-      SMDS_NodeIteratorPtr nIt = theMeshDS->nodesIterator();
-      while ( nIt->more( ))
-        if( const SMDS_MeshElement * elem = nIt->next() )
+      for ( SMDS_NodeIteratorPtr nIt = theMeshDS->nodesIterator(); nIt->more(); )
+        if ( const SMDS_MeshElement * elem = nIt->next() )
           theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
     }
     else
     {
           theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
     }
     else
     {
-      for(int i = 0; i < aElementsId->length(); i++)
-        if( const SMDS_MeshElement * elem = theMeshDS->FindElement( aElementsId[i] ))
-          theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
+      SMESH::array_of_ElementType_var types = theObject->GetTypes();
+      SMESH::long_array_var     aElementsId = theObject->GetIDs();
+      if ( types->length() == 1 && types[0] == SMESH::NODE)
+      {
+        for ( CORBA::ULong i = 0; i < aElementsId->length(); i++ )
+          if ( const SMDS_MeshNode * n = theMeshDS->FindNode( aElementsId[i] ))
+            theNodeSet.insert( theNodeSet.end(), n);
+      }
+      else
+      {
+        for ( CORBA::ULong i = 0; i < aElementsId->length(); i++ )
+          if ( const SMDS_MeshElement * elem = theMeshDS->FindElement( aElementsId[i] ))
+            theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
+      }
     }
   }
 
     }
   }
 
@@ -363,13 +345,14 @@ namespace MeshEditor_I {
     SMDSAbs_ElementType elemType    = (*theElements.begin())->GetType();
     bool sameElemType = ( elemType == (*theElements.rbegin())->GetType() );
     if ( sameElemType &&
     SMDSAbs_ElementType elemType    = (*theElements.begin())->GetType();
     bool sameElemType = ( elemType == (*theElements.rbegin())->GetType() );
     if ( sameElemType &&
-         theMeshDS->GetMeshInfo().NbElements( elemType ) == theElements.size() )
+         theMeshDS->GetMeshInfo().NbElements( elemType ) == (int) theElements.size() )
       return; // all the elements are in theElements
 
     if ( !sameElemType )
       elemType = SMDSAbs_All;
 
       return; // all the elements are in theElements
 
     if ( !sameElemType )
       elemType = SMDSAbs_All;
 
-    TIDSortedElemSet visitedNodes;
+    vector<bool> isNodeChecked( theMeshDS->NbNodes(), false );
+
     TIDSortedElemSet::const_iterator elemIt = theElements.begin();
     for ( ; elemIt != theElements.end(); ++elemIt )
     {
     TIDSortedElemSet::const_iterator elemIt = theElements.begin();
     for ( ; elemIt != theElements.end(); ++elemIt )
     {
@@ -378,8 +361,9 @@ namespace MeshEditor_I {
       while ( --i != -1 )
       {
         const SMDS_MeshNode* n = e->GetNode( i );
       while ( --i != -1 )
       {
         const SMDS_MeshNode* n = e->GetNode( i );
-        if ( visitedNodes.insert( n ).second )
+        if ( !isNodeChecked[ n->GetID() ])
         {
         {
+          isNodeChecked[ n->GetID() ] = true;
           SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator(elemType);
           while ( invIt->more() )
           {
           SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator(elemType);
           while ( invIt->more() )
           {
@@ -399,8 +383,10 @@ namespace MeshEditor_I {
    */
   //================================================================================
 
    */
   //================================================================================
 
-  string getPartIOR( SMESH::SMESH_IDSource_ptr theMeshPart, SMESH::ElementType type)
+  string getPartIOR( SMESH::SMESH_IDSource_ptr theMeshPart, SMESH::ElementType type = SMESH::ALL )
   {
   {
+    if ( SMESH::DownCast<SMESH_Mesh_i*>( theMeshPart ))
+      return "";
     string partIOR = SMESH_Gen_i::GetORB()->object_to_string( theMeshPart );
     if ( SMESH_Group_i* group_i = SMESH::DownCast<SMESH_Group_i*>( theMeshPart ))
       // take into account passible group modification
     string partIOR = SMESH_Gen_i::GetORB()->object_to_string( theMeshPart );
     if ( SMESH_Group_i* group_i = SMESH::DownCast<SMESH_Group_i*>( theMeshPart ))
       // take into account passible group modification
@@ -437,11 +423,26 @@ SMESH_MeshEditor_i::SMESH_MeshEditor_i(SMESH_Mesh_i* theMesh, bool isPreview):
 
 SMESH_MeshEditor_i::~SMESH_MeshEditor_i()
 {
 
 SMESH_MeshEditor_i::~SMESH_MeshEditor_i()
 {
-  deleteAuxIDSources();
+  PortableServer::POA_var poa = SMESH_Gen_i::GetPOA();
+  PortableServer::ObjectId_var anObjectId = poa->servant_to_id(this);
+  poa->deactivate_object(anObjectId.in());
+
+  //deleteAuxIDSources();
   delete myPreviewMesh;   myPreviewMesh = 0;
   delete myPreviewEditor; myPreviewEditor = 0;
 }
 
   delete myPreviewMesh;   myPreviewMesh = 0;
   delete myPreviewEditor; myPreviewEditor = 0;
 }
 
+//================================================================================
+/*!
+ * \brief Returns the mesh
+ */
+//================================================================================
+
+SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::GetMesh()
+{
+  return myMesh_i->_this();
+}
+
 //================================================================================
 /*!
  * \brief Clear members
 //================================================================================
 /*!
  * \brief Clear members
@@ -451,15 +452,32 @@ SMESH_MeshEditor_i::~SMESH_MeshEditor_i()
 void SMESH_MeshEditor_i::initData(bool deleteSearchers)
 {
   if ( myIsPreviewMode ) {
 void SMESH_MeshEditor_i::initData(bool deleteSearchers)
 {
   if ( myIsPreviewMode ) {
-    if ( myPreviewMesh ) myPreviewMesh->Clear();
+    if ( myPreviewMesh ) myPreviewMesh->RemoveAll();
   }
   else {
     if ( deleteSearchers )
       TSearchersDeleter::Delete();
   }
   getEditor().GetError().reset();
   }
   else {
     if ( deleteSearchers )
       TSearchersDeleter::Delete();
   }
   getEditor().GetError().reset();
-  getEditor().CrearLastCreated();
+  getEditor().ClearLastCreated();
+}
+
+//================================================================================
+/*!
+ * \brief Increment mesh modif time and optionally record that the performed
+ *        modification may influence further mesh re-compute.
+ *  \param [in] isReComputeSafe - true if the modification does not influence
+ *              further mesh re-compute
+ */
+//================================================================================
+
+void SMESH_MeshEditor_i::declareMeshModified( bool isReComputeSafe )
+{
+  myMesh->GetMeshDS()->Modified();
+  if ( !isReComputeSafe )
+    myMesh->SetIsModified( true );
 }
 }
+
 //================================================================================
 /*!
  * \brief Return either myEditor or myPreviewEditor depending on myIsPreviewMode.
 //================================================================================
 /*!
  * \brief Return either myEditor or myPreviewEditor depending on myIsPreviewMode.
@@ -481,7 +499,7 @@ void SMESH_MeshEditor_i::initData(bool deleteSearchers)
  * \brief Initialize and return myPreviewMesh
  *  \param previewElements - type of elements to show in preview
  *
  * \brief Initialize and return myPreviewMesh
  *  \param previewElements - type of elements to show in preview
  *
- *  WARNING: call it once par a method!
+ *  WARNING: call it once per method!
  */
 //================================================================================
 
  */
 //================================================================================
 
@@ -498,16 +516,6 @@ TPreviewMesh * SMESH_MeshEditor_i::getPreviewMesh(SMDSAbs_ElementType previewEle
   return myPreviewMesh;
 }
 
   return myPreviewMesh;
 }
 
-//================================================================================
-/*!
- * \brief Now does nothing
- */
-//================================================================================
-
-// void SMESH_MeshEditor_i::storeResult(::SMESH_MeshEditor& )
-// {
-// }
-
 //================================================================================
 /*!
  * Return data of mesh edition preview
 //================================================================================
 /*!
  * Return data of mesh edition preview
@@ -515,19 +523,23 @@ TPreviewMesh * SMESH_MeshEditor_i::getPreviewMesh(SMDSAbs_ElementType previewEle
 //================================================================================
 
 SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData()
 //================================================================================
 
 SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData()
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   const bool hasBadElems = ( getEditor().GetError() && getEditor().GetError()->HasBadElems() );
 
   const bool hasBadElems = ( getEditor().GetError() && getEditor().GetError()->HasBadElems() );
 
-  if ( myIsPreviewMode || hasBadElems ) { // --- MeshPreviewStruct filling ---
-
+  if ( myIsPreviewMode || hasBadElems )
+  {
     list<int> aNodesConnectivity;
     typedef map<int, int> TNodesMap;
     TNodesMap nodesMap;
 
     SMESHDS_Mesh* aMeshDS;
     list<int> aNodesConnectivity;
     typedef map<int, int> TNodesMap;
     TNodesMap nodesMap;
 
     SMESHDS_Mesh* aMeshDS;
-    std::auto_ptr< SMESH_MeshPartDS > aMeshPartDS;
+    std::unique_ptr< SMESH_MeshPartDS > aMeshPartDS;
     if ( hasBadElems ) {
     if ( hasBadElems ) {
-      aMeshPartDS.reset( new SMESH_MeshPartDS( getEditor().GetError()->myBadElements ));
+      const list<const SMDS_MeshElement*>& badElems =
+        static_cast<SMESH_BadInputElements*>( getEditor().GetError().get() )->myBadElements;
+      aMeshPartDS.reset( new SMESH_MeshPartDS( badElems ));
       aMeshDS = aMeshPartDS.get();
     }
     else {
       aMeshDS = aMeshPartDS.get();
     }
     else {
@@ -536,7 +548,7 @@ SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData()
     myPreviewData = new SMESH::MeshPreviewStruct();
     myPreviewData->nodesXYZ.length(aMeshDS->NbNodes());
 
     myPreviewData = new SMESH::MeshPreviewStruct();
     myPreviewData->nodesXYZ.length(aMeshDS->NbNodes());
 
-    
+
     SMDSAbs_ElementType previewType = SMDSAbs_All;
     if ( !hasBadElems )
       if (TPreviewMesh * aPreviewMesh = dynamic_cast< TPreviewMesh* >( getEditor().GetMesh() )) {
     SMDSAbs_ElementType previewType = SMDSAbs_All;
     if ( !hasBadElems )
       if (TPreviewMesh * aPreviewMesh = dynamic_cast< TPreviewMesh* >( getEditor().GetMesh() )) {
@@ -556,10 +568,12 @@ SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData()
 
     while ( itMeshElems->more() ) {
       const SMDS_MeshElement* aMeshElem = itMeshElems->next();
 
     while ( itMeshElems->more() ) {
       const SMDS_MeshElement* aMeshElem = itMeshElems->next();
-      SMDS_ElemIteratorPtr itElemNodes = aMeshElem->nodesIterator();
+      SMDS_NodeIteratorPtr itElemNodes = 
+        (( aMeshElem->GetEntityType() == SMDSEntity_Quad_Polygon ) ?
+         aMeshElem->interlacedNodesIterator() :
+         aMeshElem->nodeIterator() );
       while ( itElemNodes->more() ) {
       while ( itElemNodes->more() ) {
-        const SMDS_MeshNode* aMeshNode =
-          static_cast<const SMDS_MeshNode*>( itElemNodes->next() );
+        const SMDS_MeshNode* aMeshNode = itElemNodes->next();
         int aNodeID = aMeshNode->GetID();
         TNodesMap::iterator anIter = nodesMap.find(aNodeID);
         if ( anIter == nodesMap.end() ) {
         int aNodeID = aMeshNode->GetID();
         TNodesMap::iterator anIter = nodesMap.find(aNodeID);
         if ( anIter == nodesMap.end() ) {
@@ -576,12 +590,10 @@ SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData()
       // filling the elements types
       SMDSAbs_ElementType aType = aMeshElem->GetType();
       bool               isPoly = aMeshElem->IsPoly();
       // filling the elements types
       SMDSAbs_ElementType aType = aMeshElem->GetType();
       bool               isPoly = aMeshElem->IsPoly();
-
       myPreviewData->elementTypes[i].SMDS_ElementType = (SMESH::ElementType) aType;
       myPreviewData->elementTypes[i].SMDS_ElementType = (SMESH::ElementType) aType;
-      myPreviewData->elementTypes[i].isPoly = isPoly;
+      myPreviewData->elementTypes[i].isPoly           = isPoly;
       myPreviewData->elementTypes[i].nbNodesInElement = aMeshElem->NbNodes();
       i++;
       myPreviewData->elementTypes[i].nbNodesInElement = aMeshElem->NbNodes();
       i++;
-
     }
     myPreviewData->nodesXYZ.length( j );
 
     }
     myPreviewData->nodesXYZ.length( j );
 
@@ -591,8 +603,10 @@ SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData()
     for( int i = 0; aConnIter != aNodesConnectivity.end(); aConnIter++, i++ )
       myPreviewData->elementConnectivities[i] = *aConnIter;
   }
     for( int i = 0; aConnIter != aNodesConnectivity.end(); aConnIter++, i++ )
       myPreviewData->elementConnectivities[i] = *aConnIter;
   }
-
   return myPreviewData._retn();
   return myPreviewData._retn();
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -603,13 +617,19 @@ SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData()
 //================================================================================
 
 SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedNodes()
 //================================================================================
 
 SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedNodes()
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   SMESH::long_array_var myLastCreatedNodes = new SMESH::long_array();
   SMESH::long_array_var myLastCreatedNodes = new SMESH::long_array();
+
   const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedNodes();
   const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedNodes();
-  myLastCreatedNodes->length( aSeq.Length() );
-  for (int i = 1; i <= aSeq.Length(); i++)
-    myLastCreatedNodes[i-1] = aSeq.Value(i)->GetID();
+  myLastCreatedNodes->length( aSeq.size() );
+  for ( size_t i = 0; i < aSeq.size(); i++)
+    myLastCreatedNodes[i] = aSeq[i]->GetID();
+
   return myLastCreatedNodes._retn();
   return myLastCreatedNodes._retn();
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -620,23 +640,44 @@ SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedNodes()
 //================================================================================
 
 SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedElems()
 //================================================================================
 
 SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedElems()
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   SMESH::long_array_var myLastCreatedElems = new SMESH::long_array();
   SMESH::long_array_var myLastCreatedElems = new SMESH::long_array();
+
   const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
   const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
-  myLastCreatedElems->length( aSeq.Length() );
-  for ( int i = 1; i <= aSeq.Length(); i++ )
-    myLastCreatedElems[i-1] = aSeq.Value(i)->GetID();
+  myLastCreatedElems->length( aSeq.size() );
+  for ( size_t i = 0; i < aSeq.size(); i++ )
+    myLastCreatedElems[i] = aSeq[i]->GetID();
+
   return myLastCreatedElems._retn();
   return myLastCreatedElems._retn();
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
+
+//=======================================================================
+//function : ClearLastCreated
+//purpose  : Clears sequences of last created elements and nodes 
+//=======================================================================
+
+void SMESH_MeshEditor_i::ClearLastCreated() throw (SALOME::SALOME_Exception)
+{
+  SMESH_TRY;
+  getEditor().ClearLastCreated();
+  SMESH_CATCH( SMESH::throwCorbaException );
 }
 
 //=======================================================================
 /*
 }
 
 //=======================================================================
 /*
- * Returns description of an error/warning occured during the last operation
+ * Returns description of an error/warning occurred during the last operation
+ * WARNING: ComputeError.code >= 100 and no corresponding enum in IDL API
  */
 //=======================================================================
 
 SMESH::ComputeError* SMESH_MeshEditor_i::GetLastError()
  */
 //=======================================================================
 
 SMESH::ComputeError* SMESH_MeshEditor_i::GetLastError()
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   SMESH::ComputeError_var errOut = new SMESH::ComputeError;
   SMESH_ComputeErrorPtr&  errIn  = getEditor().GetError();
   if ( errIn && !errIn->IsOK() )
   SMESH::ComputeError_var errOut = new SMESH::ComputeError;
   SMESH_ComputeErrorPtr&  errIn  = getEditor().GetError();
   if ( errIn && !errIn->IsOK() )
@@ -644,7 +685,7 @@ SMESH::ComputeError* SMESH_MeshEditor_i::GetLastError()
     errOut->code       = -( errIn->myName < 0 ? errIn->myName + 1: errIn->myName ); // -1 -> 0
     errOut->comment    = errIn->myComment.c_str();
     errOut->subShapeID = -1;
     errOut->code       = -( errIn->myName < 0 ? errIn->myName + 1: errIn->myName ); // -1 -> 0
     errOut->comment    = errIn->myComment.c_str();
     errOut->subShapeID = -1;
-    errOut->hasBadMesh = !errIn->myBadElements.empty();
+    errOut->hasBadMesh = errIn->HasBadElems();
   }
   else
   {
   }
   else
   {
@@ -652,21 +693,34 @@ SMESH::ComputeError* SMESH_MeshEditor_i::GetLastError()
     errOut->subShapeID = -1;
     errOut->hasBadMesh = false;
   }
     errOut->subShapeID = -1;
     errOut->hasBadMesh = false;
   }
+
   return errOut._retn();
   return errOut._retn();
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=======================================================================
 //function : MakeIDSource
 }
 
 //=======================================================================
 //function : MakeIDSource
-//purpose  : Wrap a sequence of ids in a SMESH_IDSource
+//purpose  : Wrap a sequence of ids in a SMESH_IDSource.
+//           Call UnRegister() as you fininsh using it!!
 //=======================================================================
 
 //=======================================================================
 
-struct SMESH_MeshEditor_i::_IDSource : public POA_SMESH::SMESH_IDSource
+struct SMESH_MeshEditor_i::_IDSource : public virtual POA_SMESH::SMESH_IDSource,
+                                       public virtual SALOME::GenericObj_i
 {
   SMESH::long_array     _ids;
   SMESH::ElementType    _type;
   SMESH::SMESH_Mesh_ptr _mesh;
   SMESH::long_array* GetIDs()      { return new SMESH::long_array( _ids ); }
   SMESH::long_array* GetMeshInfo() { return 0; }
 {
   SMESH::long_array     _ids;
   SMESH::ElementType    _type;
   SMESH::SMESH_Mesh_ptr _mesh;
   SMESH::long_array* GetIDs()      { return new SMESH::long_array( _ids ); }
   SMESH::long_array* GetMeshInfo() { return 0; }
+  SMESH::long_array* GetNbElementsByType()
+  {
+    SMESH::long_array_var aRes = new SMESH::long_array();
+    aRes->length(SMESH::NB_ELEMENT_TYPES);
+    for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
+      aRes[ i ] = ( i == _type ) ? _ids.length() : 0;
+    return aRes._retn();  
+  }
   SMESH::SMESH_Mesh_ptr GetMesh()  { return SMESH::SMESH_Mesh::_duplicate( _mesh ); }
   bool IsMeshInfoCorrect()         { return true; }
   SMESH::array_of_ElementType* GetTypes()
   SMESH::SMESH_Mesh_ptr GetMesh()  { return SMESH::SMESH_Mesh::_duplicate( _mesh ); }
   bool IsMeshInfoCorrect()         { return true; }
   SMESH::array_of_ElementType* GetTypes()
@@ -678,19 +732,22 @@ struct SMESH_MeshEditor_i::_IDSource : public POA_SMESH::SMESH_IDSource
     }
     return types._retn();
   }
     }
     return types._retn();
   }
+  SALOMEDS::TMPFile* GetVtkUgStream()
+  {
+    SALOMEDS::TMPFile_var SeqFile;
+    return SeqFile._retn();
+  }
 };
 
 SMESH::SMESH_IDSource_ptr SMESH_MeshEditor_i::MakeIDSource(const SMESH::long_array& ids,
                                                            SMESH::ElementType       type)
 {
 };
 
 SMESH::SMESH_IDSource_ptr SMESH_MeshEditor_i::MakeIDSource(const SMESH::long_array& ids,
                                                            SMESH::ElementType       type)
 {
-  if ( myAuxIDSources.size() > 10 )
-    deleteAuxIDSources();
-
   _IDSource* idSrc = new _IDSource;
   idSrc->_mesh = myMesh_i->_this();
   idSrc->_ids  = ids;
   idSrc->_type = type;
   _IDSource* idSrc = new _IDSource;
   idSrc->_mesh = myMesh_i->_this();
   idSrc->_ids  = ids;
   idSrc->_type = type;
-  myAuxIDSources.push_back( idSrc );
+  if ( type == SMESH::ALL && ids.length() > 0 )
+    idSrc->_type = myMesh_i->GetElementType( ids[0], true );
 
   SMESH::SMESH_IDSource_var anIDSourceVar = idSrc->_this();
 
 
   SMESH::SMESH_IDSource_var anIDSourceVar = idSrc->_this();
 
@@ -702,14 +759,26 @@ bool SMESH_MeshEditor_i::IsTemporaryIDSource( SMESH::SMESH_IDSource_ptr& idSourc
   return SMESH::DownCast<SMESH_MeshEditor_i::_IDSource*>( idSource );
 }
 
   return SMESH::DownCast<SMESH_MeshEditor_i::_IDSource*>( idSource );
 }
 
-void SMESH_MeshEditor_i::deleteAuxIDSources()
+CORBA::Long* SMESH_MeshEditor_i::GetTemporaryIDs( SMESH::SMESH_IDSource_ptr& idSource,
+                                                  int&                       nbIds)
 {
 {
-  std::list< _IDSource* >::iterator idSrcIt = myAuxIDSources.begin();
-  for ( ; idSrcIt != myAuxIDSources.end(); ++idSrcIt )
-    delete *idSrcIt;
-  myAuxIDSources.clear();
+  if ( _IDSource* tmpIdSource = SMESH::DownCast<SMESH_MeshEditor_i::_IDSource*>( idSource ))
+  {
+    nbIds = (int) tmpIdSource->_ids.length();
+    return & tmpIdSource->_ids[0];
+  }
+  nbIds = 0;
+  return 0;
 }
 
 }
 
+// void SMESH_MeshEditor_i::deleteAuxIDSources()
+// {
+//   std::list< _IDSource* >::iterator idSrcIt = myAuxIDSources.begin();
+//   for ( ; idSrcIt != myAuxIDSources.end(); ++idSrcIt )
+//     delete *idSrcIt;
+//   myAuxIDSources.clear();
+// }
+
 //=============================================================================
 /*!
  *
 //=============================================================================
 /*!
  *
@@ -718,12 +787,14 @@ void SMESH_MeshEditor_i::deleteAuxIDSources()
 
 CORBA::Boolean
 SMESH_MeshEditor_i::RemoveElements(const SMESH::long_array & IDsOfElements)
 
 CORBA::Boolean
 SMESH_MeshEditor_i::RemoveElements(const SMESH::long_array & IDsOfElements)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   list< int > IdList;
 
   initData();
 
   list< int > IdList;
 
-  for (int i = 0; i < IDsOfElements.length(); i++)
+  for ( CORBA::ULong i = 0; i < IDsOfElements.length(); i++ )
     IdList.push_back( IDsOfElements[i] );
 
   // Update Python script
     IdList.push_back( IDsOfElements[i] );
 
   // Update Python script
@@ -731,10 +802,12 @@ SMESH_MeshEditor_i::RemoveElements(const SMESH::long_array & IDsOfElements)
 
   // Remove Elements
   bool ret = getEditor().Remove( IdList, false );
 
   // Remove Elements
   bool ret = getEditor().Remove( IdList, false );
-  myMesh->GetMeshDS()->Modified();
-  if ( IDsOfElements.length() )
-    myMesh->SetIsModified( true ); // issue 0020693
+
+  declareMeshModified( /*isReComputeSafe=*/ IDsOfElements.length() == 0 ); // issue 0020693
   return ret;
   return ret;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=============================================================================
 }
 
 //=============================================================================
@@ -744,21 +817,25 @@ SMESH_MeshEditor_i::RemoveElements(const SMESH::long_array & IDsOfElements)
 //=============================================================================
 
 CORBA::Boolean SMESH_MeshEditor_i::RemoveNodes(const SMESH::long_array & IDsOfNodes)
 //=============================================================================
 
 CORBA::Boolean SMESH_MeshEditor_i::RemoveNodes(const SMESH::long_array & IDsOfNodes)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   list< int > IdList;
   initData();
 
   list< int > IdList;
-  for (int i = 0; i < IDsOfNodes.length(); i++)
+  for ( CORBA::ULong i = 0; i < IDsOfNodes.length(); i++)
     IdList.push_back( IDsOfNodes[i] );
 
   // Update Python script
   TPythonDump() << "isDone = " << this << ".RemoveNodes( " << IDsOfNodes << " )";
 
   bool ret = getEditor().Remove( IdList, true );
     IdList.push_back( IDsOfNodes[i] );
 
   // Update Python script
   TPythonDump() << "isDone = " << this << ".RemoveNodes( " << IDsOfNodes << " )";
 
   bool ret = getEditor().Remove( IdList, true );
-  myMesh->GetMeshDS()->Modified();
-  if ( IDsOfNodes.length() )
-    myMesh->SetIsModified( true ); // issue 0020693
+
+  declareMeshModified( /*isReComputeSafe=*/ !ret ); // issue 0020693
   return ret;
   return ret;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=============================================================================
 }
 
 //=============================================================================
@@ -768,10 +845,11 @@ CORBA::Boolean SMESH_MeshEditor_i::RemoveNodes(const SMESH::long_array & IDsOfNo
 //=============================================================================
 
 CORBA::Long SMESH_MeshEditor_i::RemoveOrphanNodes()
 //=============================================================================
 
 CORBA::Long SMESH_MeshEditor_i::RemoveOrphanNodes()
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   initData();
 
-
   // Update Python script
   TPythonDump() << "nbRemoved = " << this << ".RemoveOrphanNodes()";
 
   // Update Python script
   TPythonDump() << "nbRemoved = " << this << ".RemoveOrphanNodes()";
 
@@ -781,18 +859,17 @@ CORBA::Long SMESH_MeshEditor_i::RemoveOrphanNodes()
   SMESH::Controls::Filter::GetElementsId( getMeshDS(), predicate, seq );
 
   // remove orphan nodes (if there are any)
   SMESH::Controls::Filter::GetElementsId( getMeshDS(), predicate, seq );
 
   // remove orphan nodes (if there are any)
-  list< int > IdList;
-  for ( int i = 0; i < seq.size(); i++ )
-    IdList.push_back( seq[i] );
+  list< int > IdList( seq.begin(), seq.end() );
 
   int nbNodesBefore = myMesh->NbNodes();
   getEditor().Remove( IdList, true );
 
   int nbNodesBefore = myMesh->NbNodes();
   getEditor().Remove( IdList, true );
-  myMesh->GetMeshDS()->Modified();
-  if ( IdList.size() )
-    myMesh->SetIsModified( true );
   int nbNodesAfter = myMesh->NbNodes();
 
   int nbNodesAfter = myMesh->NbNodes();
 
+  declareMeshModified( /*isReComputeSafe=*/ IdList.size() == 0 ); // issue 0020693
   return nbNodesBefore - nbNodesAfter;
   return nbNodesBefore - nbNodesAfter;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=============================================================================
 }
 
 //=============================================================================
@@ -801,9 +878,10 @@ CORBA::Long SMESH_MeshEditor_i::RemoveOrphanNodes()
  */
 //=============================================================================
 
  */
 //=============================================================================
 
-CORBA::Long SMESH_MeshEditor_i::AddNode(CORBA::Double x,
-                                        CORBA::Double y, CORBA::Double z)
+CORBA::Long SMESH_MeshEditor_i::AddNode(CORBA::Double x,CORBA::Double y, CORBA::Double z)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   const SMDS_MeshNode* N = getMeshDS()->AddNode(x, y, z);
   initData();
 
   const SMDS_MeshNode* N = getMeshDS()->AddNode(x, y, z);
@@ -812,9 +890,11 @@ CORBA::Long SMESH_MeshEditor_i::AddNode(CORBA::Double x,
   TPythonDump() << "nodeID = " << this << ".AddNode( "
                 << TVar( x ) << ", " << TVar( y ) << ", " << TVar( z )<< " )";
 
   TPythonDump() << "nodeID = " << this << ".AddNode( "
                 << TVar( x ) << ", " << TVar( y ) << ", " << TVar( z )<< " )";
 
-  myMesh->GetMeshDS()->Modified();
-  myMesh->SetIsModified( true ); // issue 0020693
+  declareMeshModified( /*isReComputeSafe=*/false );
   return N->GetID();
   return N->GetID();
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=============================================================================
 }
 
 //=============================================================================
@@ -823,22 +903,28 @@ CORBA::Long SMESH_MeshEditor_i::AddNode(CORBA::Double x,
  */
 //=============================================================================
 
  */
 //=============================================================================
 
-CORBA::Long SMESH_MeshEditor_i::Add0DElement(CORBA::Long IDOfNode)
+CORBA::Long SMESH_MeshEditor_i::Add0DElement(CORBA::Long    IDOfNode,
+                                             CORBA::Boolean DuplicateElements)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDOfNode);
   initData();
 
   const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDOfNode);
-  SMDS_MeshElement* elem = getMeshDS()->Add0DElement(aNode);
+  SMDS_ElemIteratorPtr it0D = aNode->GetInverseElementIterator( SMDSAbs_0DElement );
+  
+  SMDS_MeshElement* elem = 0;
+  if ( DuplicateElements || !it0D->more() )
+    elem = getMeshDS()->Add0DElement(aNode);
 
   // Update Python script
   TPythonDump() << "elem0d = " << this << ".Add0DElement( " << IDOfNode <<" )";
 
 
   // Update Python script
   TPythonDump() << "elem0d = " << this << ".Add0DElement( " << IDOfNode <<" )";
 
-  myMesh->GetMeshDS()->Modified();
-  myMesh->SetIsModified( true ); // issue 0020693
+  declareMeshModified( /*isReComputeSafe=*/false );
 
 
-  if (elem)
-    return elem->GetID();
+  return elem ? elem->GetID() : 0;
 
 
+  SMESH_CATCH( SMESH::throwCorbaException );
   return 0;
 }
 
   return 0;
 }
 
@@ -851,13 +937,12 @@ CORBA::Long SMESH_MeshEditor_i::Add0DElement(CORBA::Long IDOfNode)
 CORBA::Long SMESH_MeshEditor_i::AddBall(CORBA::Long IDOfNode, CORBA::Double diameter)
   throw (SALOME::SALOME_Exception)
 {
 CORBA::Long SMESH_MeshEditor_i::AddBall(CORBA::Long IDOfNode, CORBA::Double diameter)
   throw (SALOME::SALOME_Exception)
 {
+  SMESH_TRY;
   initData();
 
   if ( diameter < std::numeric_limits<double>::min() )
     THROW_SALOME_CORBA_EXCEPTION("Invalid diameter", SALOME::BAD_PARAM);
 
   initData();
 
   if ( diameter < std::numeric_limits<double>::min() )
     THROW_SALOME_CORBA_EXCEPTION("Invalid diameter", SALOME::BAD_PARAM);
 
-  SMESH_TRY;
-
   const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDOfNode);
   SMDS_MeshElement* elem = getMeshDS()->AddBall(aNode, diameter);
 
   const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDOfNode);
   SMDS_MeshElement* elem = getMeshDS()->AddBall(aNode, diameter);
 
@@ -865,14 +950,10 @@ CORBA::Long SMESH_MeshEditor_i::AddBall(CORBA::Long IDOfNode, CORBA::Double diam
   TPythonDump() << "ballElem = "
                 << this << ".AddBall( " << IDOfNode << ", " << diameter <<" )";
 
   TPythonDump() << "ballElem = "
                 << this << ".AddBall( " << IDOfNode << ", " << diameter <<" )";
 
-  myMesh->GetMeshDS()->Modified();
-  myMesh->SetIsModified( true ); // issue 0020693
-
-  if (elem)
-    return elem->GetID();
+  declareMeshModified( /*isReComputeSafe=*/false );
+  return elem ? elem->GetID() : 0;
 
   SMESH_CATCH( SMESH::throwCorbaException );
 
   SMESH_CATCH( SMESH::throwCorbaException );
-
   return 0;
 }
 
   return 0;
 }
 
@@ -884,7 +965,9 @@ CORBA::Long SMESH_MeshEditor_i::AddBall(CORBA::Long IDOfNode, CORBA::Double diam
 //=============================================================================
 
 CORBA::Long SMESH_MeshEditor_i::AddEdge(const SMESH::long_array & IDsOfNodes)
 //=============================================================================
 
 CORBA::Long SMESH_MeshEditor_i::AddEdge(const SMESH::long_array & IDsOfNodes)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   int NbNodes = IDsOfNodes.length();
   initData();
 
   int NbNodes = IDsOfNodes.length();
@@ -912,10 +995,10 @@ CORBA::Long SMESH_MeshEditor_i::AddEdge(const SMESH::long_array & IDsOfNodes)
                   <<n1<<", "<<n2<<", "<<n12<<" ])";
   }
 
                   <<n1<<", "<<n2<<", "<<n12<<" ])";
   }
 
-  myMesh->GetMeshDS()->Modified();
-  if(elem)
-    return myMesh->SetIsModified( true ), elem->GetID();
+  declareMeshModified( /*isReComputeSafe=*/false );
+  return elem ? elem->GetID() : 0;
 
 
+  SMESH_CATCH( SMESH::throwCorbaException );
   return 0;
 }
 
   return 0;
 }
 
@@ -926,7 +1009,9 @@ CORBA::Long SMESH_MeshEditor_i::AddEdge(const SMESH::long_array & IDsOfNodes)
 //=============================================================================
 
 CORBA::Long SMESH_MeshEditor_i::AddFace(const SMESH::long_array & IDsOfNodes)
 //=============================================================================
 
 CORBA::Long SMESH_MeshEditor_i::AddFace(const SMESH::long_array & IDsOfNodes)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   int NbNodes = IDsOfNodes.length();
   initData();
 
   int NbNodes = IDsOfNodes.length();
@@ -940,35 +1025,29 @@ CORBA::Long SMESH_MeshEditor_i::AddFace(const SMESH::long_array & IDsOfNodes)
     nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]);
 
   SMDS_MeshElement* elem = 0;
     nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]);
 
   SMDS_MeshElement* elem = 0;
-  if (NbNodes == 3) {
-    elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2]);
-  }
-  else if (NbNodes == 4) {
-    elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3]);
-  }
-  else if (NbNodes == 6) {
-    elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
-                                nodes[4], nodes[5]);
-  }
-  else if (NbNodes == 8) {
-    elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
-                                nodes[4], nodes[5], nodes[6], nodes[7]);
-  }
-  else if (NbNodes == 9) {
-    elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
-                                nodes[4], nodes[5], nodes[6], nodes[7], nodes[8] );
-  }
-  else if (NbNodes > 2) {
-    elem = getMeshDS()->AddPolygonalFace(nodes);
+  switch (NbNodes) {
+  case 3: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2]); break;
+  case 4: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3]); break;
+  case 6: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
+                                      nodes[4], nodes[5]); break;
+  case 7: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
+                                      nodes[4], nodes[5], nodes[6]); break;
+  case 8: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
+                                      nodes[4], nodes[5], nodes[6], nodes[7]); break;
+  case 9: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
+                                      nodes[4], nodes[5], nodes[6], nodes[7],
+                                      nodes[8] ); break;
+  default: elem = getMeshDS()->AddPolygonalFace(nodes);
   }
 
   // Update Python script
   TPythonDump() << "faceID = " << this << ".AddFace( " << IDsOfNodes << " )";
 
   }
 
   // Update Python script
   TPythonDump() << "faceID = " << this << ".AddFace( " << IDsOfNodes << " )";
 
-  myMesh->GetMeshDS()->Modified();
-  if(elem)
-    return myMesh->SetIsModified( true ), elem->GetID();
+  declareMeshModified( /*isReComputeSafe=*/false );
+
+  return elem ? elem->GetID() : 0;
 
 
+  SMESH_CATCH( SMESH::throwCorbaException );
   return 0;
 }
 
   return 0;
 }
 
@@ -977,22 +1056,58 @@ CORBA::Long SMESH_MeshEditor_i::AddFace(const SMESH::long_array & IDsOfNodes)
  *  AddPolygonalFace
  */
 //=============================================================================
  *  AddPolygonalFace
  */
 //=============================================================================
+
 CORBA::Long SMESH_MeshEditor_i::AddPolygonalFace (const SMESH::long_array & IDsOfNodes)
 CORBA::Long SMESH_MeshEditor_i::AddPolygonalFace (const SMESH::long_array & IDsOfNodes)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   int NbNodes = IDsOfNodes.length();
   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
   for (int i = 0; i < NbNodes; i++)
   initData();
 
   int NbNodes = IDsOfNodes.length();
   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
   for (int i = 0; i < NbNodes; i++)
-    nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]);
+    if ( ! ( nodes[i] = getMeshDS()->FindNode( IDsOfNodes[i] )))
+      return 0;
 
   const SMDS_MeshElement* elem = getMeshDS()->AddPolygonalFace(nodes);
 
   // Update Python script
   TPythonDump() <<"faceID = "<<this<<".AddPolygonalFace( "<<IDsOfNodes<<" )";
 
 
   const SMDS_MeshElement* elem = getMeshDS()->AddPolygonalFace(nodes);
 
   // Update Python script
   TPythonDump() <<"faceID = "<<this<<".AddPolygonalFace( "<<IDsOfNodes<<" )";
 
-  myMesh->GetMeshDS()->Modified();
-  return elem ? ( myMesh->SetIsModified( true ), elem->GetID()) : 0;
+  declareMeshModified( /*isReComputeSafe=*/false );
+  return elem ? elem->GetID() : 0;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
+
+//=============================================================================
+/*!
+ *  AddQuadPolygonalFace
+ */
+//=============================================================================
+
+CORBA::Long SMESH_MeshEditor_i::AddQuadPolygonalFace (const SMESH::long_array & IDsOfNodes)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH_TRY;
+  initData();
+
+  int NbNodes = IDsOfNodes.length();
+  std::vector<const SMDS_MeshNode*> nodes (NbNodes);
+  for (int i = 0; i < NbNodes; i++)
+    nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]);
+
+  const SMDS_MeshElement* elem = getMeshDS()->AddQuadPolygonalFace(nodes);
+
+  // Update Python script
+  TPythonDump() <<"faceID = "<<this<<".AddPolygonalFace( "<<IDsOfNodes<<" )";
+
+  declareMeshModified( /*isReComputeSafe=*/false );
+  return elem ? elem->GetID() : 0;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=============================================================================
 }
 
 //=============================================================================
@@ -1003,7 +1118,9 @@ CORBA::Long SMESH_MeshEditor_i::AddPolygonalFace (const SMESH::long_array & IDsO
 //=============================================================================
 
 CORBA::Long SMESH_MeshEditor_i::AddVolume(const SMESH::long_array & IDsOfNodes)
 //=============================================================================
 
 CORBA::Long SMESH_MeshEditor_i::AddVolume(const SMESH::long_array & IDsOfNodes)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   int NbNodes = IDsOfNodes.length();
   initData();
 
   int NbNodes = IDsOfNodes.length();
@@ -1034,6 +1151,10 @@ CORBA::Long SMESH_MeshEditor_i::AddVolume(const SMESH::long_array & IDsOfNodes)
                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
                                         n[15],n[16],n[17],n[18],n[19]);
     break;
                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
                                         n[15],n[16],n[17],n[18],n[19]);
     break;
+  case 18:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],
+                                        n[8],n[9],n[10],n[11],n[12],n[13],n[14],
+                                        n[15],n[16],n[17]);
+    break;
   case 27:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],
                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
                                         n[15],n[16],n[17],n[18],n[19],
   case 27:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],
                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
                                         n[15],n[16],n[17],n[18],n[19],
@@ -1044,10 +1165,10 @@ CORBA::Long SMESH_MeshEditor_i::AddVolume(const SMESH::long_array & IDsOfNodes)
   // Update Python script
   TPythonDump() << "volID = " << this << ".AddVolume( " << IDsOfNodes << " )";
 
   // Update Python script
   TPythonDump() << "volID = " << this << ".AddVolume( " << IDsOfNodes << " )";
 
-  myMesh->GetMeshDS()->Modified();
-  if(elem)
-    return myMesh->SetIsModified( true ), elem->GetID();
+  declareMeshModified( /*isReComputeSafe=*/false );
+  return elem ? elem->GetID() : 0;
 
 
+  SMESH_CATCH( SMESH::throwCorbaException );
   return 0;
 }
 
   return 0;
 }
 
@@ -1058,7 +1179,9 @@ CORBA::Long SMESH_MeshEditor_i::AddVolume(const SMESH::long_array & IDsOfNodes)
 //=============================================================================
 CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolume (const SMESH::long_array & IDsOfNodes,
                                                      const SMESH::long_array & Quantities)
 //=============================================================================
 CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolume (const SMESH::long_array & IDsOfNodes,
                                                      const SMESH::long_array & Quantities)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   int NbNodes = IDsOfNodes.length();
   initData();
 
   int NbNodes = IDsOfNodes.length();
@@ -1080,9 +1203,12 @@ CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolume (const SMESH::long_array & I
   // Update Python script
   TPythonDump() << "volID = " << this << ".AddPolyhedralVolume( "
                 << IDsOfNodes << ", " << Quantities << " )";
   // Update Python script
   TPythonDump() << "volID = " << this << ".AddPolyhedralVolume( "
                 << IDsOfNodes << ", " << Quantities << " )";
-  myMesh->GetMeshDS()->Modified();
 
 
-  return elem ? ( myMesh->SetIsModified( true ), elem->GetID()) : 0;
+  declareMeshModified( /*isReComputeSafe=*/false );
+  return elem ? elem->GetID() : 0;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=============================================================================
 }
 
 //=============================================================================
@@ -1092,7 +1218,9 @@ CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolume (const SMESH::long_array & I
 //=============================================================================
 
 CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolumeByFaces (const SMESH::long_array & IdsOfFaces)
 //=============================================================================
 
 CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolumeByFaces (const SMESH::long_array & IdsOfFaces)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   int NbFaces = IdsOfFaces.length();
   initData();
 
   int NbFaces = IdsOfFaces.length();
@@ -1114,18 +1242,21 @@ CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolumeByFaces (const SMESH::long_ar
   // Update Python script
   TPythonDump() << "volID = " << this << ".AddPolyhedralVolumeByFaces( "
                 << IdsOfFaces << " )";
   // Update Python script
   TPythonDump() << "volID = " << this << ".AddPolyhedralVolumeByFaces( "
                 << IdsOfFaces << " )";
-  myMesh->GetMeshDS()->Modified();
 
 
-  return elem ? ( myMesh->SetIsModified( true ), elem->GetID()) : 0;
+  declareMeshModified( /*isReComputeSafe=*/false );
+  return elem ? elem->GetID() : 0;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=============================================================================
 //
 }
 
 //=============================================================================
 //
-// \brief Create 0D elements on all nodes of the given object except those 
-//        nodes on which a 0D element already exists.
+// \brief Create 0D elements on all nodes of the given object.
 //  \param theObject object on whose nodes 0D elements will be created.
 //  \param theGroupName optional name of a group to add 0D elements created
 //         and/or found on nodes of \a theObject.
 //  \param theObject object on whose nodes 0D elements will be created.
 //  \param theGroupName optional name of a group to add 0D elements created
 //         and/or found on nodes of \a theObject.
+//  \param DuplicateElements to add one more 0D element to a node or not.
 //  \return an object (a new group or a temporary SMESH_IDSource) holding
 //          ids of new and/or found 0D elements.
 //
 //  \return an object (a new group or a temporary SMESH_IDSource) holding
 //          ids of new and/or found 0D elements.
 //
@@ -1133,19 +1264,19 @@ CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolumeByFaces (const SMESH::long_ar
 
 SMESH::SMESH_IDSource_ptr
 SMESH_MeshEditor_i::Create0DElementsOnAllNodes(SMESH::SMESH_IDSource_ptr theObject,
 
 SMESH::SMESH_IDSource_ptr
 SMESH_MeshEditor_i::Create0DElementsOnAllNodes(SMESH::SMESH_IDSource_ptr theObject,
-                                               const char*               theGroupName)
+                                               const char*               theGroupName,
+                                               CORBA::Boolean            theDuplicateElements)
   throw (SALOME::SALOME_Exception)
 {
   throw (SALOME::SALOME_Exception)
 {
+  SMESH_TRY;
   initData();
 
   SMESH::SMESH_IDSource_var result;
   TPythonDump pyDump;
 
   initData();
 
   SMESH::SMESH_IDSource_var result;
   TPythonDump pyDump;
 
-  SMESH_TRY;
-
   TIDSortedElemSet elements, elems0D;
   if ( idSourceToSet( theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
   TIDSortedElemSet elements, elems0D;
   if ( idSourceToSet( theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
-    getEditor().Create0DElementsOnAllNodes( elements, elems0D );
+    getEditor().Create0DElementsOnAllNodes( elements, elems0D, theDuplicateElements );
 
   SMESH::long_array_var newElems = new SMESH::long_array;
   newElems->length( elems0D.size() );
 
   SMESH::long_array_var newElems = new SMESH::long_array;
   newElems->length( elems0D.size() );
@@ -1189,9 +1320,10 @@ SMESH_MeshEditor_i::Create0DElementsOnAllNodes(SMESH::SMESH_IDSource_ptr theObje
   pyDump << " = " << this << ".Create0DElementsOnAllNodes( "
          << theObject << ", '" << theGroupName << "' )";
 
   pyDump << " = " << this << ".Create0DElementsOnAllNodes( "
          << theObject << ", '" << theGroupName << "' )";
 
-  SMESH_CATCH( SMESH::throwCorbaException );
-
   return result._retn();
   return result._retn();
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=============================================================================
 }
 
 //=============================================================================
@@ -1206,7 +1338,7 @@ SMESH_MeshEditor_i::Create0DElementsOnAllNodes(SMESH::SMESH_IDSource_ptr theObje
 void SMESH_MeshEditor_i::SetNodeOnVertex(CORBA::Long NodeID, CORBA::Long VertexID)
   throw (SALOME::SALOME_Exception)
 {
 void SMESH_MeshEditor_i::SetNodeOnVertex(CORBA::Long NodeID, CORBA::Long VertexID)
   throw (SALOME::SALOME_Exception)
 {
-  Unexpect aCatch(SALOME_SalomeException);
+  SMESH_TRY;
 
   SMESHDS_Mesh * mesh = getMeshDS();
   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
 
   SMESHDS_Mesh * mesh = getMeshDS();
   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
@@ -1223,6 +1355,8 @@ void SMESH_MeshEditor_i::SetNodeOnVertex(CORBA::Long NodeID, CORBA::Long VertexI
   mesh->SetNodeOnVertex( node, VertexID );
 
   myMesh->SetIsModified( true );
   mesh->SetNodeOnVertex( node, VertexID );
 
   myMesh->SetIsModified( true );
+
+  SMESH_CATCH( SMESH::throwCorbaException );
 }
 
 //=============================================================================
 }
 
 //=============================================================================
@@ -1239,7 +1373,7 @@ void SMESH_MeshEditor_i::SetNodeOnEdge(CORBA::Long NodeID, CORBA::Long EdgeID,
                                        CORBA::Double paramOnEdge)
   throw (SALOME::SALOME_Exception)
 {
                                        CORBA::Double paramOnEdge)
   throw (SALOME::SALOME_Exception)
 {
-  Unexpect aCatch(SALOME_SalomeException);
+  SMESH_TRY;
 
   SMESHDS_Mesh * mesh = getMeshDS();
   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
 
   SMESHDS_Mesh * mesh = getMeshDS();
   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
@@ -1261,6 +1395,8 @@ void SMESH_MeshEditor_i::SetNodeOnEdge(CORBA::Long NodeID, CORBA::Long EdgeID,
   mesh->SetNodeOnEdge( node, EdgeID, paramOnEdge );
 
   myMesh->SetIsModified( true );
   mesh->SetNodeOnEdge( node, EdgeID, paramOnEdge );
 
   myMesh->SetIsModified( true );
+
+  SMESH_CATCH( SMESH::throwCorbaException );
 }
 
 //=============================================================================
 }
 
 //=============================================================================
@@ -1278,8 +1414,7 @@ void SMESH_MeshEditor_i::SetNodeOnFace(CORBA::Long NodeID, CORBA::Long FaceID,
                                        CORBA::Double u, CORBA::Double v)
   throw (SALOME::SALOME_Exception)
 {
                                        CORBA::Double u, CORBA::Double v)
   throw (SALOME::SALOME_Exception)
 {
-  Unexpect aCatch(SALOME_SalomeException);
-
+  SMESH_TRY;
   SMESHDS_Mesh * mesh = getMeshDS();
   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
   if ( !node )
   SMESHDS_Mesh * mesh = getMeshDS();
   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
   if ( !node )
@@ -1311,6 +1446,8 @@ void SMESH_MeshEditor_i::SetNodeOnFace(CORBA::Long NodeID, CORBA::Long FaceID,
 
   mesh->SetNodeOnFace( node, FaceID, u, v );
   myMesh->SetIsModified( true );
 
   mesh->SetNodeOnFace( node, FaceID, u, v );
   myMesh->SetIsModified( true );
+
+  SMESH_CATCH( SMESH::throwCorbaException );
 }
 
 //=============================================================================
 }
 
 //=============================================================================
@@ -1325,8 +1462,7 @@ void SMESH_MeshEditor_i::SetNodeOnFace(CORBA::Long NodeID, CORBA::Long FaceID,
 void SMESH_MeshEditor_i::SetNodeInVolume(CORBA::Long NodeID, CORBA::Long SolidID)
   throw (SALOME::SALOME_Exception)
 {
 void SMESH_MeshEditor_i::SetNodeInVolume(CORBA::Long NodeID, CORBA::Long SolidID)
   throw (SALOME::SALOME_Exception)
 {
-  Unexpect aCatch(SALOME_SalomeException);
-
+  SMESH_TRY;
   SMESHDS_Mesh * mesh = getMeshDS();
   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
   if ( !node )
   SMESHDS_Mesh * mesh = getMeshDS();
   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
   if ( !node )
@@ -1342,7 +1478,7 @@ void SMESH_MeshEditor_i::SetNodeInVolume(CORBA::Long NodeID, CORBA::Long SolidID
 
   mesh->SetNodeInVolume( node, SolidID );
 
 
   mesh->SetNodeInVolume( node, SolidID );
 
-  // myMesh->SetIsModified( true ); - SetNodeInVolume() can't prevent re-compute, I believe
+  SMESH_CATCH( SMESH::throwCorbaException );
 }
 
 //=============================================================================
 }
 
 //=============================================================================
@@ -1350,7 +1486,6 @@ void SMESH_MeshEditor_i::SetNodeInVolume(CORBA::Long NodeID, CORBA::Long SolidID
  * \brief Bind an element to a shape
  * \param ElementID - element ID
  * \param ShapeID - shape ID available through GEOM_Object.GetSubShapeIndices()[0]
  * \brief Bind an element to a shape
  * \param ElementID - element ID
  * \param ShapeID - shape ID available through GEOM_Object.GetSubShapeIndices()[0]
- * \retval boolean - false if ElementID or ShapeID is invalid
  */
 //=============================================================================
 
  */
 //=============================================================================
 
@@ -1358,14 +1493,13 @@ void SMESH_MeshEditor_i::SetMeshElementOnShape(CORBA::Long ElementID,
                                                CORBA::Long ShapeID)
   throw (SALOME::SALOME_Exception)
 {
                                                CORBA::Long ShapeID)
   throw (SALOME::SALOME_Exception)
 {
-  Unexpect aCatch(SALOME_SalomeException);
-
+  SMESH_TRY;
   SMESHDS_Mesh * mesh = getMeshDS();
   SMDS_MeshElement* elem = const_cast<SMDS_MeshElement*>(mesh->FindElement(ElementID));
   if ( !elem )
     THROW_SALOME_CORBA_EXCEPTION("Invalid ElementID", SALOME::BAD_PARAM);
 
   SMESHDS_Mesh * mesh = getMeshDS();
   SMDS_MeshElement* elem = const_cast<SMDS_MeshElement*>(mesh->FindElement(ElementID));
   if ( !elem )
     THROW_SALOME_CORBA_EXCEPTION("Invalid ElementID", SALOME::BAD_PARAM);
 
-  if ( mesh->MaxShapeIndex() < ShapeID )
+  if ( mesh->MaxShapeIndex() < ShapeID || ShapeID < 1 )
     THROW_SALOME_CORBA_EXCEPTION("Invalid ShapeID", SALOME::BAD_PARAM);
 
   TopoDS_Shape shape = mesh->IndexToShape( ShapeID );
     THROW_SALOME_CORBA_EXCEPTION("Invalid ShapeID", SALOME::BAD_PARAM);
 
   TopoDS_Shape shape = mesh->IndexToShape( ShapeID );
@@ -1378,6 +1512,8 @@ void SMESH_MeshEditor_i::SetMeshElementOnShape(CORBA::Long ElementID,
   mesh->SetMeshElementOnShape( elem, ShapeID );
 
   myMesh->SetIsModified( true );
   mesh->SetMeshElementOnShape( elem, ShapeID );
 
   myMesh->SetIsModified( true );
+
+  SMESH_CATCH( SMESH::throwCorbaException );
 }
 
 //=============================================================================
 }
 
 //=============================================================================
@@ -1388,7 +1524,9 @@ void SMESH_MeshEditor_i::SetMeshElementOnShape(CORBA::Long ElementID,
 
 CORBA::Boolean SMESH_MeshEditor_i::InverseDiag(CORBA::Long NodeID1,
                                                CORBA::Long NodeID2)
 
 CORBA::Boolean SMESH_MeshEditor_i::InverseDiag(CORBA::Long NodeID1,
                                                CORBA::Long NodeID2)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   const SMDS_MeshNode * n1 = getMeshDS()->FindNode( NodeID1 );
   initData();
 
   const SMDS_MeshNode * n1 = getMeshDS()->FindNode( NodeID1 );
@@ -1400,11 +1538,13 @@ CORBA::Boolean SMESH_MeshEditor_i::InverseDiag(CORBA::Long NodeID1,
   TPythonDump() << "isDone = " << this << ".InverseDiag( "
                 << NodeID1 << ", " << NodeID2 << " )";
 
   TPythonDump() << "isDone = " << this << ".InverseDiag( "
                 << NodeID1 << ", " << NodeID2 << " )";
 
-
   int ret =  getEditor().InverseDiag ( n1, n2 );
   int ret =  getEditor().InverseDiag ( n1, n2 );
-  myMesh->GetMeshDS()->Modified();
-  myMesh->SetIsModified( true );
+
+  declareMeshModified( /*isReComputeSafe=*/false );
   return ret;
   return ret;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=============================================================================
 }
 
 //=============================================================================
@@ -1415,7 +1555,9 @@ CORBA::Boolean SMESH_MeshEditor_i::InverseDiag(CORBA::Long NodeID1,
 
 CORBA::Boolean SMESH_MeshEditor_i::DeleteDiag(CORBA::Long NodeID1,
                                               CORBA::Long NodeID2)
 
 CORBA::Boolean SMESH_MeshEditor_i::DeleteDiag(CORBA::Long NodeID1,
                                               CORBA::Long NodeID2)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   const SMDS_MeshNode * n1 = getMeshDS()->FindNode( NodeID1 );
   initData();
 
   const SMDS_MeshNode * n1 = getMeshDS()->FindNode( NodeID1 );
@@ -1430,12 +1572,12 @@ CORBA::Boolean SMESH_MeshEditor_i::DeleteDiag(CORBA::Long NodeID1,
 
   bool stat = getEditor().DeleteDiag ( n1, n2 );
 
 
   bool stat = getEditor().DeleteDiag ( n1, n2 );
 
-  myMesh->GetMeshDS()->Modified();
-  if ( stat )
-    myMesh->SetIsModified( true ); // issue 0020693
-
+  declareMeshModified( /*isReComputeSafe=*/!stat );
 
   return stat;
 
   return stat;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=============================================================================
 }
 
 //=============================================================================
@@ -1445,10 +1587,12 @@ CORBA::Boolean SMESH_MeshEditor_i::DeleteDiag(CORBA::Long NodeID1,
 //=============================================================================
 
 CORBA::Boolean SMESH_MeshEditor_i::Reorient(const SMESH::long_array & IDsOfElements)
 //=============================================================================
 
 CORBA::Boolean SMESH_MeshEditor_i::Reorient(const SMESH::long_array & IDsOfElements)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   initData();
 
-  for (int i = 0; i < IDsOfElements.length(); i++)
+  for ( CORBA::ULong i = 0; i < IDsOfElements.length(); i++ )
   {
     CORBA::Long index = IDsOfElements[i];
     const SMDS_MeshElement * elem = getMeshDS()->FindElement(index);
   {
     CORBA::Long index = IDsOfElements[i];
     const SMDS_MeshElement * elem = getMeshDS()->FindElement(index);
@@ -1458,13 +1602,12 @@ CORBA::Boolean SMESH_MeshEditor_i::Reorient(const SMESH::long_array & IDsOfEleme
   // Update Python script
   TPythonDump() << "isDone = " << this << ".Reorient( " << IDsOfElements << " )";
 
   // Update Python script
   TPythonDump() << "isDone = " << this << ".Reorient( " << IDsOfElements << " )";
 
-  myMesh->GetMeshDS()->Modified();
-  if ( IDsOfElements.length() )
-    myMesh->SetIsModified( true ); // issue 0020693
-
+  declareMeshModified( /*isReComputeSafe=*/ IDsOfElements.length() == 0 );
   return true;
   return true;
-}
 
 
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
 
 //=============================================================================
 /*!
 
 //=============================================================================
 /*!
@@ -1473,18 +1616,26 @@ CORBA::Boolean SMESH_MeshEditor_i::Reorient(const SMESH::long_array & IDsOfEleme
 //=============================================================================
 
 CORBA::Boolean SMESH_MeshEditor_i::ReorientObject(SMESH::SMESH_IDSource_ptr theObject)
 //=============================================================================
 
 CORBA::Boolean SMESH_MeshEditor_i::ReorientObject(SMESH::SMESH_IDSource_ptr theObject)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   TPythonDump aTPythonDump; // suppress dump in Reorient()
 
   initData();
 
   TPythonDump aTPythonDump; // suppress dump in Reorient()
 
+  prepareIdSource( theObject );
+
   SMESH::long_array_var anElementsId = theObject->GetIDs();
   CORBA::Boolean isDone = Reorient(anElementsId);
 
   // Update Python script
   aTPythonDump << "isDone = " << this << ".ReorientObject( " << theObject << " )";
 
   SMESH::long_array_var anElementsId = theObject->GetIDs();
   CORBA::Boolean isDone = Reorient(anElementsId);
 
   // Update Python script
   aTPythonDump << "isDone = " << this << ".ReorientObject( " << theObject << " )";
 
+  declareMeshModified( /*isReComputeSafe=*/ anElementsId->length() == 0 );
   return isDone;
   return isDone;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=======================================================================
 }
 
 //=======================================================================
@@ -1504,12 +1655,15 @@ CORBA::Long SMESH_MeshEditor_i::Reorient2D(SMESH::SMESH_IDSource_ptr the2Dgroup,
                                            const SMESH::PointStruct& thePoint)
   throw (SALOME::SALOME_Exception)
 {
                                            const SMESH::PointStruct& thePoint)
   throw (SALOME::SALOME_Exception)
 {
-  Unexpect aCatch(SALOME_SalomeException);
-
+  SMESH_TRY;
   initData(/*deleteSearchers=*/false);
 
   TIDSortedElemSet elements;
   initData(/*deleteSearchers=*/false);
 
   TIDSortedElemSet elements;
-  if ( !idSourceToSet( the2Dgroup, getMeshDS(), elements, SMDSAbs_Face, /*emptyIfIsMesh=*/1))
+  IDSource_Error error;
+  idSourceToSet( the2Dgroup, getMeshDS(), elements, SMDSAbs_Face, /*emptyIfIsMesh=*/1, &error );
+  if ( error == IDSource_EMPTY )
+    return 0;
+  if ( error == IDSource_INVALID )
     THROW_SALOME_CORBA_EXCEPTION("No faces in given group", SALOME::BAD_PARAM);
 
 
     THROW_SALOME_CORBA_EXCEPTION("No faces in given group", SALOME::BAD_PARAM);
 
 
@@ -1533,14 +1687,14 @@ CORBA::Long SMESH_MeshEditor_i::Reorient2D(SMESH::SMESH_IDSource_ptr the2Dgroup,
         if ( myMesh->NbFaces() == 0 )
           THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM);
 
         if ( myMesh->NbFaces() == 0 )
           THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM);
 
-        theElementSearcher = myEditor.GetElementSearcher();
+        theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
       }
       else
       {
         typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
         SMDS_ElemIteratorPtr elemsIt( new TIter( elements.begin(), elements.end() ));
 
       }
       else
       {
         typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
         SMDS_ElemIteratorPtr elemsIt( new TIter( elements.begin(), elements.end() ));
 
-        theElementSearcher = myEditor.GetElementSearcher(elemsIt);
+        theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemsIt);
       }
     }
     // find a face
       }
     }
     // find a face
@@ -1561,8 +1715,7 @@ CORBA::Long SMESH_MeshEditor_i::Reorient2D(SMESH::SMESH_IDSource_ptr the2Dgroup,
   int nbReori = getEditor().Reorient2D( elements, dirVec, face );
 
   if ( nbReori ) {
   int nbReori = getEditor().Reorient2D( elements, dirVec, face );
 
   if ( nbReori ) {
-    myMesh->SetIsModified( true );
-    myMesh->GetMeshDS()->Modified();
+    declareMeshModified( /*isReComputeSafe=*/false );
   }
   TPythonDump() << this << ".Reorient2D( "
                 << the2Dgroup << ", "
   }
   TPythonDump() << this << ".Reorient2D( "
                 << the2Dgroup << ", "
@@ -1571,22 +1724,86 @@ CORBA::Long SMESH_MeshEditor_i::Reorient2D(SMESH::SMESH_IDSource_ptr the2Dgroup,
                 << thePoint << " )";
 
   return nbReori;
                 << thePoint << " )";
 
   return nbReori;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
+
+//=======================================================================
+//function : Reorient2DBy3D
+//purpose  : Reorient faces basing on orientation of adjacent volumes.
+//=======================================================================
+
+CORBA::Long SMESH_MeshEditor_i::Reorient2DBy3D(const SMESH::ListOfIDSources& faceGroups,
+                                               SMESH::SMESH_IDSource_ptr     volumeGroup,
+                                               CORBA::Boolean                outsideNormal)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH_TRY;
+  initData();
+
+  TIDSortedElemSet volumes;
+  IDSource_Error volsError;
+  idSourceToSet( volumeGroup, getMeshDS(), volumes, SMDSAbs_Volume, /*emptyIfMesh=*/1, &volsError);
+
+  int nbReori = 0;
+  for ( size_t i = 0; i < faceGroups.length(); ++i )
+  {
+    SMESH::SMESH_IDSource_ptr faceGrp = faceGroups[i].in();
+
+    TIDSortedElemSet faces;
+    IDSource_Error error;
+    idSourceToSet( faceGrp, getMeshDS(), faces, SMDSAbs_Face, /*emptyIfIsMesh=*/1, &error );
+    if ( error == IDSource_INVALID && faceGroups.length() == 1 )
+      THROW_SALOME_CORBA_EXCEPTION("No faces in a given object", SALOME::BAD_PARAM);
+    if ( error == IDSource_OK && volsError != IDSource_OK )
+      THROW_SALOME_CORBA_EXCEPTION("No volumes in a given object", SALOME::BAD_PARAM);
+
+    nbReori += getEditor().Reorient2DBy3D( faces, volumes, outsideNormal );
+
+    if ( error != IDSource_EMPTY && faces.empty() ) // all faces in the mesh treated
+      break;
+  }
+
+  if ( nbReori ) {
+    declareMeshModified( /*isReComputeSafe=*/false );
+  }
+  TPythonDump() << this << ".Reorient2DBy3D( "
+                << faceGroups << ", "
+                << volumeGroup << ", "
+                << outsideNormal << " )";
+
+  return nbReori;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=============================================================================
 /*!
 }
 
 //=============================================================================
 /*!
- *
+ * \brief Fuse neighbour triangles into quadrangles.
  */
 //=============================================================================
  */
 //=============================================================================
+
 CORBA::Boolean SMESH_MeshEditor_i::TriToQuad (const SMESH::long_array &   IDsOfElements,
                                               SMESH::NumericalFunctor_ptr Criterion,
                                               CORBA::Double               MaxAngle)
 CORBA::Boolean SMESH_MeshEditor_i::TriToQuad (const SMESH::long_array &   IDsOfElements,
                                               SMESH::NumericalFunctor_ptr Criterion,
                                               CORBA::Double               MaxAngle)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   SMESHDS_Mesh* aMesh = getMeshDS();
   initData();
 
   SMESHDS_Mesh* aMesh = getMeshDS();
-  TIDSortedElemSet faces;
-  arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face);
+  TIDSortedElemSet faces,copyFaces;
+  SMDS_MeshElement::GeomFilter triaFilter(SMDSGeom_TRIANGLE);
+  arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face, & triaFilter);
+  TIDSortedElemSet* workElements = & faces;
+
+  if ( myIsPreviewMode ) {
+    SMDSAbs_ElementType select =  SMDSAbs_Face;
+    getPreviewMesh( SMDSAbs_Face )->Copy( faces, copyFaces, select );
+    workElements = & copyFaces;
+  }
 
   SMESH::NumericalFunctor_i* aNumericalFunctor =
     dynamic_cast<SMESH::NumericalFunctor_i*>( SMESH_Gen_i::GetServant( Criterion ).in() );
 
   SMESH::NumericalFunctor_i* aNumericalFunctor =
     dynamic_cast<SMESH::NumericalFunctor_i*>( SMESH_Gen_i::GetServant( Criterion ).in() );
@@ -1596,55 +1813,67 @@ CORBA::Boolean SMESH_MeshEditor_i::TriToQuad (const SMESH::long_array &   IDsOfE
   else
     aCrit = aNumericalFunctor->GetNumericalFunctor();
 
   else
     aCrit = aNumericalFunctor->GetNumericalFunctor();
 
-  // Update Python script
-  TPythonDump() << "isDone = " << this << ".TriToQuad( "
-                << IDsOfElements << ", " << aNumericalFunctor << ", " << TVar( MaxAngle ) << " )";
-
-
-  bool stat = getEditor().TriToQuad( faces, aCrit, MaxAngle );
-  myMesh->GetMeshDS()->Modified();
-  if ( stat )
-    myMesh->SetIsModified( true ); // issue 0020693
+  if ( !myIsPreviewMode ) {
+    // Update Python script
+    TPythonDump() << "isDone = " << this << ".TriToQuad( "
+                  << IDsOfElements << ", " << aNumericalFunctor << ", " << TVar( MaxAngle ) << " )";
+  }
 
 
+  bool stat = getEditor().TriToQuad( *workElements, aCrit, MaxAngle );
 
 
+  declareMeshModified( /*isReComputeSafe=*/!stat );
   return stat;
   return stat;
-}
 
 
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
 
 //=============================================================================
 /*!
 
 //=============================================================================
 /*!
- *
+ * \brief Fuse neighbour triangles into quadrangles.
  */
 //=============================================================================
  */
 //=============================================================================
+
 CORBA::Boolean SMESH_MeshEditor_i::TriToQuadObject (SMESH::SMESH_IDSource_ptr   theObject,
                                                     SMESH::NumericalFunctor_ptr Criterion,
                                                     CORBA::Double               MaxAngle)
 CORBA::Boolean SMESH_MeshEditor_i::TriToQuadObject (SMESH::SMESH_IDSource_ptr   theObject,
                                                     SMESH::NumericalFunctor_ptr Criterion,
                                                     CORBA::Double               MaxAngle)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   TPythonDump aTPythonDump;  // suppress dump in TriToQuad()
   initData();
 
   TPythonDump aTPythonDump;  // suppress dump in TriToQuad()
+
+  prepareIdSource( theObject );
   SMESH::long_array_var anElementsId = theObject->GetIDs();
   CORBA::Boolean isDone = TriToQuad(anElementsId, Criterion, MaxAngle);
 
   SMESH::long_array_var anElementsId = theObject->GetIDs();
   CORBA::Boolean isDone = TriToQuad(anElementsId, Criterion, MaxAngle);
 
-  SMESH::NumericalFunctor_i* aNumericalFunctor =
-    SMESH::DownCast<SMESH::NumericalFunctor_i*>( Criterion );
+  if ( !myIsPreviewMode ) {
+    SMESH::NumericalFunctor_i* aNumericalFunctor =
+      SMESH::DownCast<SMESH::NumericalFunctor_i*>( Criterion );
 
 
-  // Update Python script
-  aTPythonDump << "isDone = " << this << ".TriToQuadObject("
-               << theObject << ", " << aNumericalFunctor << ", " << TVar( MaxAngle ) << " )";
+    // Update Python script
+    aTPythonDump << "isDone = " << this << ".TriToQuadObject("
+                 << theObject << ", " << aNumericalFunctor << ", " << TVar( MaxAngle ) << " )";
+  }
 
   return isDone;
 
   return isDone;
-}
 
 
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
 
 //=============================================================================
 /*!
 
 //=============================================================================
 /*!
- *
+ * \brief Split quadrangles into triangles.
  */
 //=============================================================================
  */
 //=============================================================================
+
 CORBA::Boolean SMESH_MeshEditor_i::QuadToTri (const SMESH::long_array &   IDsOfElements,
                                               SMESH::NumericalFunctor_ptr Criterion)
 CORBA::Boolean SMESH_MeshEditor_i::QuadToTri (const SMESH::long_array &   IDsOfElements,
                                               SMESH::NumericalFunctor_ptr Criterion)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   SMESHDS_Mesh* aMesh = getMeshDS();
   initData();
 
   SMESHDS_Mesh* aMesh = getMeshDS();
@@ -1664,27 +1893,30 @@ CORBA::Boolean SMESH_MeshEditor_i::QuadToTri (const SMESH::long_array &   IDsOfE
   TPythonDump() << "isDone = " << this << ".QuadToTri( " << IDsOfElements << ", " << aNumericalFunctor << " )";
 
   CORBA::Boolean stat = getEditor().QuadToTri( faces, aCrit );
   TPythonDump() << "isDone = " << this << ".QuadToTri( " << IDsOfElements << ", " << aNumericalFunctor << " )";
 
   CORBA::Boolean stat = getEditor().QuadToTri( faces, aCrit );
-  myMesh->GetMeshDS()->Modified();
-  if ( stat )
-    myMesh->SetIsModified( true ); // issue 0020693
-
 
 
+  declareMeshModified( /*isReComputeSafe=*/false );
   return stat;
   return stat;
-}
 
 
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
 
 //=============================================================================
 /*!
 
 //=============================================================================
 /*!
- *
+ * \brief Split quadrangles into triangles.
  */
 //=============================================================================
  */
 //=============================================================================
+
 CORBA::Boolean SMESH_MeshEditor_i::QuadToTriObject (SMESH::SMESH_IDSource_ptr   theObject,
                                                     SMESH::NumericalFunctor_ptr Criterion)
 CORBA::Boolean SMESH_MeshEditor_i::QuadToTriObject (SMESH::SMESH_IDSource_ptr   theObject,
                                                     SMESH::NumericalFunctor_ptr Criterion)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   TPythonDump aTPythonDump;  // suppress dump in QuadToTri()
 
   initData();
 
   TPythonDump aTPythonDump;  // suppress dump in QuadToTri()
 
+  prepareIdSource( theObject );
   SMESH::long_array_var anElementsId = theObject->GetIDs();
   CORBA::Boolean isDone = QuadToTri(anElementsId, Criterion);
 
   SMESH::long_array_var anElementsId = theObject->GetIDs();
   CORBA::Boolean isDone = QuadToTri(anElementsId, Criterion);
 
@@ -1694,18 +1926,48 @@ CORBA::Boolean SMESH_MeshEditor_i::QuadToTriObject (SMESH::SMESH_IDSource_ptr
   // Update Python script
   aTPythonDump << "isDone = " << this << ".QuadToTriObject( " << theObject << ", " << aNumericalFunctor << " )";
 
   // Update Python script
   aTPythonDump << "isDone = " << this << ".QuadToTriObject( " << theObject << ", " << aNumericalFunctor << " )";
 
+  declareMeshModified( /*isReComputeSafe=*/false );
   return isDone;
   return isDone;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 }
 
+//================================================================================
+/*!
+ * \brief Split each of quadrangles into 4 triangles.
+ *  \param [in] theObject - theQuads Container of quadrangles to split.
+ */
+//================================================================================
+
+void SMESH_MeshEditor_i::QuadTo4Tri (SMESH::SMESH_IDSource_ptr theObject)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH_TRY;
+  initData();
+
+  TIDSortedElemSet faces;
+  if ( !idSourceToSet( theObject, getMeshDS(), faces, SMDSAbs_Face, /*emptyIfIsMesh=*/true ) &&
+       faces.empty() )
+    THROW_SALOME_CORBA_EXCEPTION("No faces given", SALOME::BAD_PARAM);
+
+  getEditor().QuadTo4Tri( faces );
+  TPythonDump() << this << ".QuadTo4Tri( " << theObject << " )";
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+}
 
 //=============================================================================
 /*!
 
 //=============================================================================
 /*!
- *
+ * \brief Split quadrangles into triangles.
  */
 //=============================================================================
  */
 //=============================================================================
+
 CORBA::Boolean SMESH_MeshEditor_i::SplitQuad (const SMESH::long_array & IDsOfElements,
                                               CORBA::Boolean            Diag13)
 CORBA::Boolean SMESH_MeshEditor_i::SplitQuad (const SMESH::long_array & IDsOfElements,
                                               CORBA::Boolean            Diag13)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   SMESHDS_Mesh* aMesh = getMeshDS();
   initData();
 
   SMESHDS_Mesh* aMesh = getMeshDS();
@@ -1717,28 +1979,30 @@ CORBA::Boolean SMESH_MeshEditor_i::SplitQuad (const SMESH::long_array & IDsOfEle
                 << IDsOfElements << ", " << Diag13 << " )";
 
   CORBA::Boolean stat = getEditor().QuadToTri( faces, Diag13 );
                 << IDsOfElements << ", " << Diag13 << " )";
 
   CORBA::Boolean stat = getEditor().QuadToTri( faces, Diag13 );
-  myMesh->GetMeshDS()->Modified();
-  if ( stat )
-    myMesh->SetIsModified( true ); // issue 0020693
-
-
 
 
+  declareMeshModified( /*isReComputeSafe=*/ !stat );
   return stat;
   return stat;
-}
 
 
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
 
 //=============================================================================
 /*!
 
 //=============================================================================
 /*!
- *
+ * \brief Split quadrangles into triangles.
  */
 //=============================================================================
  */
 //=============================================================================
+
 CORBA::Boolean SMESH_MeshEditor_i::SplitQuadObject (SMESH::SMESH_IDSource_ptr theObject,
                                                     CORBA::Boolean            Diag13)
 CORBA::Boolean SMESH_MeshEditor_i::SplitQuadObject (SMESH::SMESH_IDSource_ptr theObject,
                                                     CORBA::Boolean            Diag13)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   TPythonDump aTPythonDump;  // suppress dump in SplitQuad()
 
   initData();
 
   TPythonDump aTPythonDump;  // suppress dump in SplitQuad()
 
+  prepareIdSource( theObject );
   SMESH::long_array_var anElementsId = theObject->GetIDs();
   CORBA::Boolean isDone = SplitQuad(anElementsId, Diag13);
 
   SMESH::long_array_var anElementsId = theObject->GetIDs();
   CORBA::Boolean isDone = SplitQuad(anElementsId, Diag13);
 
@@ -1746,18 +2010,29 @@ CORBA::Boolean SMESH_MeshEditor_i::SplitQuadObject (SMESH::SMESH_IDSource_ptr th
   aTPythonDump << "isDone = " << this << ".SplitQuadObject( "
                << theObject << ", " << Diag13 << " )";
 
   aTPythonDump << "isDone = " << this << ".SplitQuadObject( "
                << theObject << ", " << Diag13 << " )";
 
+  declareMeshModified( /*isReComputeSafe=*/!isDone );
   return isDone;
   return isDone;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 
 //=============================================================================
 /*!
 }
 
 
 //=============================================================================
 /*!
- *  BestSplit
+ * Find better splitting of the given quadrangle.
+ *  \param IDOfQuad  ID of the quadrangle to be split.
+ *  \param Criterion A criterion to choose a diagonal for splitting.
+ *  \return 1 if 1-3 diagonal is better, 2 if 2-4
+ *          diagonal is better, 0 if error occurs.
  */
 //=============================================================================
  */
 //=============================================================================
+
 CORBA::Long SMESH_MeshEditor_i::BestSplit (CORBA::Long                 IDOfQuad,
                                            SMESH::NumericalFunctor_ptr Criterion)
 CORBA::Long SMESH_MeshEditor_i::BestSplit (CORBA::Long                 IDOfQuad,
                                            SMESH::NumericalFunctor_ptr Criterion)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   const SMDS_MeshElement* quad = getMeshDS()->FindElement(IDOfQuad);
   initData();
 
   const SMDS_MeshElement* quad = getMeshDS()->FindElement(IDOfQuad);
@@ -1771,9 +2046,13 @@ CORBA::Long SMESH_MeshEditor_i::BestSplit (CORBA::Long                 IDOfQuad,
     else
       aCrit.reset(new SMESH::Controls::AspectRatio());
 
     else
       aCrit.reset(new SMESH::Controls::AspectRatio());
 
-    return getEditor().BestSplit(quad, aCrit);
+    int id = getEditor().BestSplit(quad, aCrit);
+    declareMeshModified( /*isReComputeSafe=*/ id < 1 );
+    return id;
   }
   }
-  return -1;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -1786,23 +2065,126 @@ void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems,
                                                 CORBA::Short              methodFlags)
   throw (SALOME::SALOME_Exception)
 {
                                                 CORBA::Short              methodFlags)
   throw (SALOME::SALOME_Exception)
 {
-  Unexpect aCatch(SALOME_SalomeException);
-
+  SMESH_TRY;
   initData();
 
   initData();
 
+  ::SMESH_MeshEditor::TFacetOfElem elemSet;
+  const int noneFacet = -1;
+  prepareIdSource( elems );
+  if ( SMDS_ElemIteratorPtr volIt = myMesh_i->GetElements( elems, SMESH::VOLUME ))
+    while ( volIt->more() )
+      elemSet.insert( elemSet.end(), make_pair( volIt->next(), noneFacet ));
+
+  getEditor().SplitVolumes( elemSet, int( methodFlags ));
+  declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
+
+  TPythonDump() << this << ".SplitVolumesIntoTetra( "
+                << elems << ", " << methodFlags << " )";
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+}
+
+//================================================================================
+/*!
+ * \brief Split hexahedra into triangular prisms
+ *  \param elems - elements to split
+ *  \param facetToSplitNormal - normal used to find a facet of hexahedron
+ *         to split into triangles
+ *  \param methodFlags - flags passing splitting method:
+ *         1 - split the hexahedron into 2 prisms
+ *         2 - split the hexahedron into 4 prisms
+ */
+//================================================================================
+
+void SMESH_MeshEditor_i::SplitHexahedraIntoPrisms( SMESH::SMESH_IDSource_ptr  elems,
+                                                   const SMESH::PointStruct & startHexPoint,
+                                                   const SMESH::DirStruct&    facetToSplitNormal,
+                                                   CORBA::Short               methodFlags,
+                                                   CORBA::Boolean             allDomains)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH_TRY;
+  initData();
+  prepareIdSource( elems );
+
+  gp_Ax1 facetNorm( gp_Pnt( startHexPoint.x,
+                            startHexPoint.y,
+                            startHexPoint.z ),
+                    gp_Dir( facetToSplitNormal.PS.x,
+                            facetToSplitNormal.PS.y,
+                            facetToSplitNormal.PS.z ));
+  TIDSortedElemSet elemSet;
+  prepareIdSource( elems );
   SMESH::long_array_var anElementsId = elems->GetIDs();
   SMESH::long_array_var anElementsId = elems->GetIDs();
+  SMDS_MeshElement::GeomFilter filter( SMDSGeom_HEXA );
+  arrayToSet( anElementsId, getMeshDS(), elemSet, SMDSAbs_Volume, &filter );
+
+  ::SMESH_MeshEditor::TFacetOfElem elemFacets;
+  while ( !elemSet.empty() )
+  {
+    getEditor().GetHexaFacetsToSplit( elemSet, facetNorm, elemFacets );
+    if ( !allDomains )
+      break;
+
+    ::SMESH_MeshEditor::TFacetOfElem::iterator ef = elemFacets.begin();
+    for ( ; ef != elemFacets.end(); ++ef )
+      elemSet.erase( ef->first );
+  }
+
+  if ( methodFlags == 2 )
+    methodFlags = int( ::SMESH_MeshEditor::HEXA_TO_4_PRISMS );
+  else
+    methodFlags = int( ::SMESH_MeshEditor::HEXA_TO_2_PRISMS );
+
+  getEditor().SplitVolumes( elemFacets, int( methodFlags ));
+  declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
+
+  TPythonDump() << this << ".SplitHexahedraIntoPrisms( "
+                << elems << ", "
+                << startHexPoint << ", "
+                << facetToSplitNormal<< ", "
+                << methodFlags<< ", "
+                << allDomains << " )";
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+}
+
+//================================================================================
+/*!
+ * \brief Split bi-quadratic elements into linear ones without creation of additional nodes:
+ *   - bi-quadratic triangle will be split into 3 linear quadrangles;
+ *   - bi-quadratic quadrangle will be split into 4 linear quadrangles;
+ *   - tri-quadratic hexahedron will be split into 8 linear hexahedra.
+ *   Quadratic elements of lower dimension  adjacent to the split bi-quadratic element
+ *   will be split in order to keep the mesh conformal.
+ *  \param elems - elements to split
+ */
+//================================================================================
+
+void SMESH_MeshEditor_i::SplitBiQuadraticIntoLinear(const SMESH::ListOfIDSources& theElems)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH_TRY;
+  initData();
+
   TIDSortedElemSet elemSet;
   TIDSortedElemSet elemSet;
-  arrayToSet( anElementsId, getMeshDS(), elemSet, SMDSAbs_Volume );
+  for ( size_t i = 0; i < theElems.length(); ++i )
+  {
+    SMESH::SMESH_IDSource_ptr elems = theElems[i].in();
+    SMESH::SMESH_Mesh_var      mesh = elems->GetMesh();
+    if ( mesh->GetId() != myMesh_i->GetId() )
+      THROW_SALOME_CORBA_EXCEPTION("Wrong mesh of IDSource", SALOME::BAD_PARAM);
 
 
-  getEditor().SplitVolumesIntoTetra( elemSet, int( methodFlags ));
-  myMesh->GetMeshDS()->Modified();
+    idSourceToSet( elems, getMeshDS(), elemSet, SMDSAbs_All );
+  }
+  getEditor().SplitBiQuadraticIntoLinear( elemSet );
 
 
+  declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
 
 
-//   if ( myLastCreatedElems.length() ) - it does not influence Compute()
-//     myMesh->SetIsModified( true ); // issue 0020693
+  TPythonDump() << this << ".SplitBiQuadraticIntoLinear( "
+                << theElems << " )";
 
 
-  TPythonDump() << this << ".SplitVolumesIntoTetra( "
-                << elems << ", " << methodFlags << " )";
+  SMESH_CATCH( SMESH::throwCorbaException );
 }
 
 //=======================================================================
 }
 
 //=======================================================================
@@ -1816,6 +2198,7 @@ SMESH_MeshEditor_i::Smooth(const SMESH::long_array &              IDsOfElements,
                            CORBA::Long                            MaxNbOfIterations,
                            CORBA::Double                          MaxAspectRatio,
                            SMESH::SMESH_MeshEditor::Smooth_Method Method)
                            CORBA::Long                            MaxNbOfIterations,
                            CORBA::Double                          MaxAspectRatio,
                            SMESH::SMESH_MeshEditor::Smooth_Method Method)
+  throw (SALOME::SALOME_Exception)
 {
   return smooth( IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations,
                  MaxAspectRatio, Method, false );
 {
   return smooth( IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations,
                  MaxAspectRatio, Method, false );
@@ -1833,6 +2216,7 @@ SMESH_MeshEditor_i::SmoothParametric(const SMESH::long_array &              IDsO
                                      CORBA::Long                            MaxNbOfIterations,
                                      CORBA::Double                          MaxAspectRatio,
                                      SMESH::SMESH_MeshEditor::Smooth_Method Method)
                                      CORBA::Long                            MaxNbOfIterations,
                                      CORBA::Double                          MaxAspectRatio,
                                      SMESH::SMESH_MeshEditor::Smooth_Method Method)
+  throw (SALOME::SALOME_Exception)
 {
   return smooth( IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations,
                  MaxAspectRatio, Method, true );
 {
   return smooth( IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations,
                  MaxAspectRatio, Method, true );
@@ -1850,6 +2234,7 @@ SMESH_MeshEditor_i::SmoothObject(SMESH::SMESH_IDSource_ptr              theObjec
                                  CORBA::Long                            MaxNbOfIterations,
                                  CORBA::Double                          MaxAspectRatio,
                                  SMESH::SMESH_MeshEditor::Smooth_Method Method)
                                  CORBA::Long                            MaxNbOfIterations,
                                  CORBA::Double                          MaxAspectRatio,
                                  SMESH::SMESH_MeshEditor::Smooth_Method Method)
+  throw (SALOME::SALOME_Exception)
 {
   return smoothObject (theObject, IDsOfFixedNodes, MaxNbOfIterations,
                        MaxAspectRatio, Method, false);
 {
   return smoothObject (theObject, IDsOfFixedNodes, MaxNbOfIterations,
                        MaxAspectRatio, Method, false);
@@ -1867,6 +2252,7 @@ SMESH_MeshEditor_i::SmoothParametricObject(SMESH::SMESH_IDSource_ptr
                                            CORBA::Long                            MaxNbOfIterations,
                                            CORBA::Double                          MaxAspectRatio,
                                            SMESH::SMESH_MeshEditor::Smooth_Method Method)
                                            CORBA::Long                            MaxNbOfIterations,
                                            CORBA::Double                          MaxAspectRatio,
                                            SMESH::SMESH_MeshEditor::Smooth_Method Method)
+  throw (SALOME::SALOME_Exception)
 {
   return smoothObject (theObject, IDsOfFixedNodes, MaxNbOfIterations,
                        MaxAspectRatio, Method, true);
 {
   return smoothObject (theObject, IDsOfFixedNodes, MaxNbOfIterations,
                        MaxAspectRatio, Method, true);
@@ -1886,7 +2272,9 @@ SMESH_MeshEditor_i::smooth(const SMESH::long_array &              IDsOfElements,
                            CORBA::Double                          MaxAspectRatio,
                            SMESH::SMESH_MeshEditor::Smooth_Method Method,
                            bool                                   IsParametric)
                            CORBA::Double                          MaxAspectRatio,
                            SMESH::SMESH_MeshEditor::Smooth_Method Method,
                            bool                                   IsParametric)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   SMESHDS_Mesh* aMesh = getMeshDS();
   initData();
 
   SMESHDS_Mesh* aMesh = getMeshDS();
@@ -1895,7 +2283,7 @@ SMESH_MeshEditor_i::smooth(const SMESH::long_array &              IDsOfElements,
   arrayToSet(IDsOfElements, aMesh, elements, SMDSAbs_Face);
 
   set<const SMDS_MeshNode*> fixedNodes;
   arrayToSet(IDsOfElements, aMesh, elements, SMDSAbs_Face);
 
   set<const SMDS_MeshNode*> fixedNodes;
-  for (int i = 0; i < IDsOfFixedNodes.length(); i++) {
+  for ( CORBA::ULong i = 0; i < IDsOfFixedNodes.length(); i++) {
     CORBA::Long index = IDsOfFixedNodes[i];
     const SMDS_MeshNode * node = aMesh->FindNode(index);
     if ( node )
     CORBA::Long index = IDsOfFixedNodes[i];
     const SMDS_MeshNode * node = aMesh->FindNode(index);
     if ( node )
@@ -1908,9 +2296,7 @@ SMESH_MeshEditor_i::smooth(const SMESH::long_array &              IDsOfElements,
   getEditor().Smooth(elements, fixedNodes, method,
                   MaxNbOfIterations, MaxAspectRatio, IsParametric );
 
   getEditor().Smooth(elements, fixedNodes, method,
                   MaxNbOfIterations, MaxAspectRatio, IsParametric );
 
-  myMesh->GetMeshDS()->Modified();
-  myMesh->SetIsModified( true ); // issue 0020693
-
+  declareMeshModified( /*isReComputeSafe=*/true ); // does not prevent re-compute
 
   // Update Python script
   TPythonDump() << "isDone = " << this << "."
 
   // Update Python script
   TPythonDump() << "isDone = " << this << "."
@@ -1922,8 +2308,10 @@ SMESH_MeshEditor_i::smooth(const SMESH::long_array &              IDsOfElements,
                      "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
 
   return true;
                      "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
 
   return true;
-}
 
 
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
 
 //=============================================================================
 /*!
 
 //=============================================================================
 /*!
@@ -1938,11 +2326,14 @@ SMESH_MeshEditor_i::smoothObject(SMESH::SMESH_IDSource_ptr              theObjec
                                  CORBA::Double                          MaxAspectRatio,
                                  SMESH::SMESH_MeshEditor::Smooth_Method Method,
                                  bool                                   IsParametric)
                                  CORBA::Double                          MaxAspectRatio,
                                  SMESH::SMESH_MeshEditor::Smooth_Method Method,
                                  bool                                   IsParametric)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   TPythonDump aTPythonDump;  // suppress dump in smooth()
 
   initData();
 
   TPythonDump aTPythonDump;  // suppress dump in smooth()
 
+  prepareIdSource( theObject );
   SMESH::long_array_var anElementsId = theObject->GetIDs();
   CORBA::Boolean isDone = smooth (anElementsId, IDsOfFixedNodes, MaxNbOfIterations,
                                   MaxAspectRatio, Method, IsParametric);
   SMESH::long_array_var anElementsId = theObject->GetIDs();
   CORBA::Boolean isDone = smooth (anElementsId, IDsOfFixedNodes, MaxNbOfIterations,
                                   MaxAspectRatio, Method, IsParametric);
@@ -1957,8 +2348,10 @@ SMESH_MeshEditor_i::smoothObject(SMESH::SMESH_IDSource_ptr              theObjec
                     "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
 
   return isDone;
                     "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
 
   return isDone;
-}
 
 
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
 
 //=============================================================================
 /*!
 
 //=============================================================================
 /*!
@@ -1967,13 +2360,16 @@ SMESH_MeshEditor_i::smoothObject(SMESH::SMESH_IDSource_ptr              theObjec
 //=============================================================================
 
 void SMESH_MeshEditor_i::RenumberNodes()
 //=============================================================================
 
 void SMESH_MeshEditor_i::RenumberNodes()
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   // Update Python script
   TPythonDump() << this << ".RenumberNodes()";
 
   getMeshDS()->Renumber( true );
   // Update Python script
   TPythonDump() << this << ".RenumberNodes()";
 
   getMeshDS()->Renumber( true );
-}
 
 
+  SMESH_CATCH( SMESH::throwCorbaException );
+}
 
 //=============================================================================
 /*!
 
 //=============================================================================
 /*!
@@ -1982,11 +2378,15 @@ void SMESH_MeshEditor_i::RenumberNodes()
 //=============================================================================
 
 void SMESH_MeshEditor_i::RenumberElements()
 //=============================================================================
 
 void SMESH_MeshEditor_i::RenumberElements()
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   // Update Python script
   TPythonDump() << this << ".RenumberElements()";
 
   getMeshDS()->Renumber( false );
   // Update Python script
   TPythonDump() << this << ".RenumberElements()";
 
   getMeshDS()->Renumber( false );
+
+  SMESH_CATCH( SMESH::throwCorbaException );
 }
 
 //=======================================================================
 }
 
 //=======================================================================
@@ -1996,1644 +2396,1404 @@ void SMESH_MeshEditor_i::RenumberElements()
 //=======================================================================
 
 SMESH::ListOfGroups* SMESH_MeshEditor_i::getGroups(const std::list<int>* groupIDs)
 //=======================================================================
 
 SMESH::ListOfGroups* SMESH_MeshEditor_i::getGroups(const std::list<int>* groupIDs)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   if ( !groupIDs )
     return 0;
   myMesh_i->CreateGroupServants();
   return myMesh_i->GetGroups( *groupIDs );
   if ( !groupIDs )
     return 0;
   myMesh_i->CreateGroupServants();
   return myMesh_i->GetGroups( *groupIDs );
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : rotationSweep
+//function : RotationSweepObjects
 //purpose  :
 //=======================================================================
 
 SMESH::ListOfGroups*
 //purpose  :
 //=======================================================================
 
 SMESH::ListOfGroups*
-SMESH_MeshEditor_i::rotationSweep(const SMESH::long_array & theIDsOfElements,
-                                  const SMESH::AxisStruct & theAxis,
-                                  CORBA::Double             theAngleInRadians,
-                                  CORBA::Long               theNbOfSteps,
-                                  CORBA::Double             theTolerance,
-                                  const bool                theMakeGroups,
-                                  const SMDSAbs_ElementType theElementType)
+SMESH_MeshEditor_i::RotationSweepObjects(const SMESH::ListOfIDSources & theNodes,
+                                         const SMESH::ListOfIDSources & theEdges,
+                                         const SMESH::ListOfIDSources & theFaces,
+                                         const SMESH::AxisStruct &      theAxis,
+                                         CORBA::Double                  theAngleInRadians,
+                                         CORBA::Long                    theNbOfSteps,
+                                         CORBA::Double                  theTolerance,
+                                         const bool                     theMakeGroups)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   initData();
 
-  TIDSortedElemSet inElements, copyElements;
-  arrayToSet(theIDsOfElements, getMeshDS(), inElements, theElementType);
+  TIDSortedElemSet elemsNodes[2];
+  for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
+    if ( SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE ))
+      while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
+  }
+  for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
+    idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
+  for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
+    idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
 
 
-  TIDSortedElemSet* workElements = & inElements;
+  TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
   bool              makeWalls=true;
   if ( myIsPreviewMode )
   {
     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
   bool              makeWalls=true;
   if ( myIsPreviewMode )
   {
     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
-    getPreviewMesh( SMDSAbs_Face )->Copy( inElements, copyElements, select, avoid );
-    workElements = & copyElements;
-    //makeWalls = false;
+    TPreviewMesh * tmpMesh = getPreviewMesh();
+    tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
+    tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
+    workElements = & copyElements[0];
+    //makeWalls = false; -- faces are needed for preview
   }
 
   }
 
+  TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
+
   gp_Ax1 Ax1 (gp_Pnt( theAxis.x,  theAxis.y,  theAxis.z ),
               gp_Vec( theAxis.vx, theAxis.vy, theAxis.vz ));
 
   ::SMESH_MeshEditor::PGroupIDs groupIds =
   gp_Ax1 Ax1 (gp_Pnt( theAxis.x,  theAxis.y,  theAxis.z ),
               gp_Vec( theAxis.vx, theAxis.vy, theAxis.vz ));
 
   ::SMESH_MeshEditor::PGroupIDs groupIds =
-      getEditor().RotationSweep (*workElements, Ax1, theAngleInRadians,
+      getEditor().RotationSweep (workElements, Ax1, theAngleInRadians,
                                  theNbOfSteps, theTolerance, theMakeGroups, makeWalls);
                                  theNbOfSteps, theTolerance, theMakeGroups, makeWalls);
-  myMesh->GetMeshDS()->Modified();
-
-  //  myMesh->SetIsModified( true ); -- it does not influence Compute()
 
 
-  return theMakeGroups ? getGroups(groupIds.get()) : 0;
-}
+  SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0;
 
 
-//=======================================================================
-//function : RotationSweep
-//purpose  :
-//=======================================================================
+  declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
 
 
-void SMESH_MeshEditor_i::RotationSweep(const SMESH::long_array & theIDsOfElements,
-                                       const SMESH::AxisStruct & theAxis,
-                                       CORBA::Double             theAngleInRadians,
-                                       CORBA::Long               theNbOfSteps,
-                                       CORBA::Double             theTolerance)
-{
-  if ( !myIsPreviewMode ) {
-    TPythonDump() << this << ".RotationSweep( "
-                  << theIDsOfElements          << ", "
-                  << theAxis                   << ", "
-                  << TVar( theAngleInRadians ) << ", "
-                  << TVar( theNbOfSteps      ) << ", "
-                  << TVar( theTolerance      ) << " )";
+  if ( !myIsPreviewMode )
+  {
+    dumpGroupsList( aPythonDump, aGroups );
+    aPythonDump << this<< ".RotationSweepObjects( "
+                << theNodes                  << ", "
+                << theEdges                  << ", "
+                << theFaces                  << ", "
+                << theAxis                   << ", "
+                << TVar( theAngleInRadians ) << ", "
+                << TVar( theNbOfSteps      ) << ", "
+                << TVar( theTolerance      ) << ", "
+                << theMakeGroups             << " )";
+  }
+  else
+  {
+    getPreviewMesh()->Remove( SMDSAbs_Volume );
   }
   }
-  rotationSweep(theIDsOfElements,
-                theAxis,
-                theAngleInRadians,
-                theNbOfSteps,
-                theTolerance,
-                false);
-}
-
-//=======================================================================
-//function : RotationSweepMakeGroups
-//purpose  :
-//=======================================================================
 
 
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::RotationSweepMakeGroups(const SMESH::long_array& theIDsOfElements,
-                                            const SMESH::AxisStruct& theAxis,
-                                            CORBA::Double            theAngleInRadians,
-                                            CORBA::Long              theNbOfSteps,
-                                            CORBA::Double            theTolerance)
-{
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+  return aGroups ? aGroups : new SMESH::ListOfGroups;
 
 
-  SMESH::ListOfGroups *aGroups = rotationSweep(theIDsOfElements,
-                                               theAxis,
-                                               theAngleInRadians,
-                                               theNbOfSteps,
-                                               theTolerance,
-                                               true);
-  if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".RotationSweepMakeGroups( "
-                << theIDsOfElements        << ", "
-                << theAxis                   << ", "
-                << TVar( theAngleInRadians ) << ", "
-                << TVar( theNbOfSteps      ) << ", "
-                << TVar( theTolerance      ) << " )";
-  }
-  return aGroups;
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 }
 
-//=======================================================================
-//function : RotationSweepObject
-//purpose  :
-//=======================================================================
-
-void SMESH_MeshEditor_i::RotationSweepObject(SMESH::SMESH_IDSource_ptr theObject,
-                                             const SMESH::AxisStruct & theAxis,
-                                             CORBA::Double             theAngleInRadians,
-                                             CORBA::Long               theNbOfSteps,
-                                             CORBA::Double             theTolerance)
+namespace MeshEditor_I
 {
 {
-  if ( !myIsPreviewMode ) {
-    TPythonDump() << this << ".RotationSweepObject( "
-                  << theObject << ", "
-                  << theAxis << ", "
-                  << theAngleInRadians << ", "
-                  << theNbOfSteps << ", "
-                  << theTolerance << " )";
-  }
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  rotationSweep(anElementsId,
-                theAxis,
-                theAngleInRadians,
-                theNbOfSteps,
-                theTolerance,
-                false);
-}
+  /*!
+   * \brief Structure used to pass extrusion parameters to ::SMESH_MeshEditor
+   */
+  struct ExtrusionParams : public ::SMESH_MeshEditor::ExtrusParam
+  {
+    bool myIsExtrusionByNormal;
+
+    static int makeFlags( CORBA::Boolean MakeGroups,
+                          CORBA::Boolean ScaleVariation = false,
+                          CORBA::Boolean AngleVariation = false,
+                          CORBA::Boolean ByAverageNormal = false,
+                          CORBA::Boolean UseInputElemsOnly = false,
+                          CORBA::Long    Flags = 0,
+                          CORBA::Boolean MakeBoundary = true )
+    {
+      if ( MakeGroups       ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS;
+      if ( ByAverageNormal  ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BY_AVG_NORMAL;
+      if ( UseInputElemsOnly) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY;
+      if ( ScaleVariation  )  Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_SCALE_LINEAR_VARIATION;
+      if ( AngleVariation  )  Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_ANGLE_LINEAR_VARIATION;
+      if ( MakeBoundary     ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BOUNDARY;
+      return Flags;
+    }
+    // standard params
+    ExtrusionParams(const SMESH::DirStruct &    theDir,
+                    CORBA::Long                 theNbOfSteps,
+                    const SMESH::double_array & theScaleFactors,
+                    CORBA::Boolean              theScaleVariation,
+                    const SMESH::double_array & theAngles,
+                    CORBA::Boolean              theAngleVariation,
+                    const SMESH::double_array & theBasePoint,
+                    CORBA::Boolean              theMakeGroups):
+      ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
+                                                theDir.PS.y,
+                                                theDir.PS.z ),
+                                        theNbOfSteps,
+                                        toList( theScaleFactors ),
+                                        toList( theAngles ),
+                                        TBasePoint( theBasePoint ),
+                                        makeFlags( theMakeGroups, theScaleVariation, theAngleVariation )),
+      myIsExtrusionByNormal( false )
+    {
+    }
+    // advanced params
+    ExtrusionParams(const SMESH::DirStruct &  theDir,
+                    CORBA::Long               theNbOfSteps,
+                    CORBA::Boolean            theMakeGroups,
+                    CORBA::Long               theExtrFlags,
+                    CORBA::Double             theSewTolerance):
+      ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
+                                                theDir.PS.y,
+                                                theDir.PS.z ),
+                                        theNbOfSteps,
+                                        std::list<double>(),
+                                        std::list<double>(),
+                                        0,
+                                        makeFlags( theMakeGroups, false, false, false, false,
+                                                   theExtrFlags, false ),
+                                        theSewTolerance ),
+      myIsExtrusionByNormal( false )
+    {
+    }
+    // params for extrusion by normal
+    ExtrusionParams(CORBA::Double  theStepSize,
+                    CORBA::Long    theNbOfSteps,
+                    CORBA::Short   theDim,
+                    CORBA::Boolean theByAverageNormal,
+                    CORBA::Boolean theUseInputElemsOnly,
+                    CORBA::Boolean theMakeGroups ):
+      ::SMESH_MeshEditor::ExtrusParam ( theStepSize, 
+                                        theNbOfSteps,
+                                        makeFlags( theMakeGroups, false, false,
+                                                   theByAverageNormal, theUseInputElemsOnly ),
+                                        theDim),
+      myIsExtrusionByNormal( true )
+    {
+    }
 
 
-//=======================================================================
-//function : RotationSweepObject1D
-//purpose  :
-//=======================================================================
+    void SetNoGroups()
+    {
+      Flags() &= ~(::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS);
+    }
 
 
-void SMESH_MeshEditor_i::RotationSweepObject1D(SMESH::SMESH_IDSource_ptr theObject,
-                                               const SMESH::AxisStruct & theAxis,
-                                               CORBA::Double             theAngleInRadians,
-                                               CORBA::Long               theNbOfSteps,
-                                               CORBA::Double             theTolerance)
-{
-  if ( !myIsPreviewMode ) {
-    TPythonDump() << this << ".RotationSweepObject1D( "
-                  << theObject                 << ", "
-                  << theAxis                   << ", "
-                  << TVar( theAngleInRadians ) << ", "
-                  << TVar( theNbOfSteps      ) << ", "
-                  << TVar( theTolerance      ) << " )";
-  }
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  rotationSweep(anElementsId,
-                theAxis,
-                theAngleInRadians,
-                theNbOfSteps,
-                theTolerance,
-                false,
-                SMDSAbs_Edge);
-}
+    static std::list<double> toList( const SMESH::double_array & theScaleFactors )
+    {
+      std::list<double> scales;
+      for ( CORBA::ULong i = 0; i < theScaleFactors.length(); ++i )
+        scales.push_back( theScaleFactors[i] );
+      return scales;
+    }
 
 
-//=======================================================================
-//function : RotationSweepObject2D
-//purpose  :
-//=======================================================================
+  private:
 
 
-void SMESH_MeshEditor_i::RotationSweepObject2D(SMESH::SMESH_IDSource_ptr theObject,
-                                               const SMESH::AxisStruct & theAxis,
-                                               CORBA::Double             theAngleInRadians,
-                                               CORBA::Long               theNbOfSteps,
-                                               CORBA::Double             theTolerance)
-{
-  if ( !myIsPreviewMode ) {
-    TPythonDump() << this << ".RotationSweepObject2D( "
-                  << theObject                 << ", "
-                  << theAxis                   << ", "
-                  << TVar( theAngleInRadians ) << ", "
-                  << TVar( theNbOfSteps      ) << ", "
-                  << TVar( theTolerance      ) << " )";
-  }
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  rotationSweep(anElementsId,
-                theAxis,
-                theAngleInRadians,
-                theNbOfSteps,
-                theTolerance,
-                false,
-                SMDSAbs_Face);
+    // structure used to convert SMESH::double_array to gp_XYZ*
+    struct TBasePoint
+    {
+      gp_XYZ *pp, p;
+      TBasePoint( const SMESH::double_array & theBasePoint )
+      {
+        pp = 0;
+        if ( theBasePoint.length() == 3 )
+        {
+          p.SetCoord( theBasePoint[0], theBasePoint[1], theBasePoint[2] );
+          pp = &p;
+        }
+      }
+      operator const gp_XYZ*() const { return pp; }
+    };
+  };
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : RotationSweepObjectMakeGroups
-//purpose  :
+/*!
+ * \brief Generate dim+1 elements by extrusion of elements along vector
+ *  \param [in] edges - edges to extrude: a list including groups, sub-meshes or a mesh
+ *  \param [in] faces - faces to extrude: a list including groups, sub-meshes or a mesh
+ *  \param [in] nodes - nodes to extrude: a list including groups, sub-meshes or a mesh
+ *  \param [in] stepVector - vector giving direction and distance of an extrusion step
+ *  \param [in] nbOfSteps - number of elements to generate from one element
+ *  \param [in] toMakeGroups - if true, new elements will be included into new groups
+ *              corresponding to groups the input elements included in.
+ *  \return ListOfGroups - new groups created if \a toMakeGroups is true
+ */
 //=======================================================================
 
 SMESH::ListOfGroups*
 //=======================================================================
 
 SMESH::ListOfGroups*
-SMESH_MeshEditor_i::RotationSweepObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
-                                                  const SMESH::AxisStruct&  theAxis,
-                                                  CORBA::Double             theAngleInRadians,
-                                                  CORBA::Long               theNbOfSteps,
-                                                  CORBA::Double             theTolerance)
+SMESH_MeshEditor_i::ExtrusionSweepObjects(const SMESH::ListOfIDSources & theNodes,
+                                          const SMESH::ListOfIDSources & theEdges,
+                                          const SMESH::ListOfIDSources & theFaces,
+                                          const SMESH::DirStruct &       theStepVector,
+                                          CORBA::Long                    theNbOfSteps,
+                                          CORBA::Boolean                 theToMakeGroups,
+                                          const SMESH::double_array &    theScaleFactors,
+                                          CORBA::Boolean                 theScalesVariation,
+                                          const SMESH::double_array &    theBasePoint,
+                                          const SMESH::double_array &    theAngles,
+                                          CORBA::Boolean                 theAnglesVariation)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+  SMESH_TRY;
+  initData();
 
 
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  SMESH::ListOfGroups *aGroups = rotationSweep(anElementsId,
-                                               theAxis,
-                                               theAngleInRadians,
-                                               theNbOfSteps,
-                                               theTolerance,
-                                               true);
-  if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".RotationSweepObjectMakeGroups( "
-                << theObject << ", "
-                << theAxis << ", "
-                << theAngleInRadians << ", "
-                << theNbOfSteps << ", "
-                << theTolerance << " )";
+  ExtrusionParams params( theStepVector, theNbOfSteps, theScaleFactors, theScalesVariation,
+                          theAngles, theAnglesVariation, theBasePoint, theToMakeGroups );
+
+  TIDSortedElemSet elemsNodes[2];
+  for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
+    if ( SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE ))
+      while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
   }
   }
-  return aGroups;
-}
+  for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
+    idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
+  for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
+    idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
 
 
-//=======================================================================
-//function : RotationSweepObject1DMakeGroups
-//purpose  :
-//=======================================================================
+  TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
+  SMDSAbs_ElementType previewType = SMDSAbs_All; //SMDSAbs_Face;
+  if ( myIsPreviewMode )
+  {
+    // if ( (*elemsNodes.begin())->GetType() == SMDSAbs_Node )
+    //   previewType = SMDSAbs_Edge;
 
 
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::RotationSweepObject1DMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
-                                                    const SMESH::AxisStruct&  theAxis,
-                                                    CORBA::Double             theAngleInRadians,
-                                                    CORBA::Long               theNbOfSteps,
-                                                    CORBA::Double             theTolerance)
-{
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+    SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
+    TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
+    tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
+    tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
+    workElements = & copyElements[0];
 
 
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  SMESH::ListOfGroups *aGroups = rotationSweep(anElementsId,
-                                               theAxis,
-                                               theAngleInRadians,
-                                               theNbOfSteps,
-                                               theTolerance,
-                                               true,
-                                               SMDSAbs_Edge);
-  if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".RotationSweepObject1DMakeGroups( "
-                << theObject                 << ", "
-                << theAxis                   << ", "
-                << TVar( theAngleInRadians ) << ", "
-                << TVar( theNbOfSteps )      << ", "
-                << TVar( theTolerance )      << " )";
+    params.SetNoGroups();
   }
   }
-  return aGroups;
-}
+  TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
 
 
-//=======================================================================
-//function : RotationSweepObject2DMakeGroups
-//purpose  :
-//=======================================================================
+  ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
+  ::SMESH_MeshEditor::PGroupIDs groupIds =
+      getEditor().ExtrusionSweep( workElements, params, aHistory );
 
 
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::RotationSweepObject2DMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
-                                                    const SMESH::AxisStruct&  theAxis,
-                                                    CORBA::Double             theAngleInRadians,
-                                                    CORBA::Long               theNbOfSteps,
-                                                    CORBA::Double             theTolerance)
-{
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+  SMESH::ListOfGroups * aGroups = theToMakeGroups ? getGroups( groupIds.get()) : 0;
 
 
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  SMESH::ListOfGroups *aGroups = rotationSweep(anElementsId,
-                                               theAxis,
-                                               theAngleInRadians,
-                                               theNbOfSteps,
-                                               theTolerance,
-                                               true,
-                                               SMDSAbs_Face);
-  if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".RotationSweepObject2DMakeGroups( "
-                << theObject                 << ", "
-                << theAxis                   << ", "
-                << TVar( theAngleInRadians ) << ", "
-                << TVar( theNbOfSteps      ) << ", "
-                << TVar( theTolerance      ) << " )";
+  declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
+
+  if ( !myIsPreviewMode )
+  {
+    dumpGroupsList( aPythonDump, aGroups );
+    aPythonDump << this<< ".ExtrusionSweepObjects( "
+                << theNodes                << ", "
+                << theEdges                << ", "
+                << theFaces                << ", "
+                << theStepVector           << ", "
+                << TVar( theNbOfSteps )    << ", "
+                << theToMakeGroups         << ", "
+                << TVar( theScaleFactors ) << ", "
+                << theScalesVariation      << ", "
+                << TVar( theBasePoint )    << ", "
+                << TVar( theAngles )       << ", "
+                << theAnglesVariation      << " )";
   }
   }
-  return aGroups;
-}
+  else
+  {
+    getPreviewMesh( previewType )->Remove( SMDSAbs_Volume );
+  }
+
+  return aGroups ? aGroups : new SMESH::ListOfGroups;
 
 
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
 
 //=======================================================================
 
 //=======================================================================
-//function : extrusionSweep
+//function : ExtrusionByNormal
 //purpose  :
 //=======================================================================
 
 SMESH::ListOfGroups*
 //purpose  :
 //=======================================================================
 
 SMESH::ListOfGroups*
-SMESH_MeshEditor_i::extrusionSweep(const SMESH::long_array & theIDsOfElements,
-                                   const SMESH::DirStruct &  theStepVector,
-                                   CORBA::Long               theNbOfSteps,
-                                   bool                      theMakeGroups,
-                                   const SMDSAbs_ElementType theElementType)
+SMESH_MeshEditor_i::ExtrusionByNormal(const SMESH::ListOfIDSources& objects,
+                                      CORBA::Double                 stepSize,
+                                      CORBA::Long                   nbOfSteps,
+                                      CORBA::Boolean                byAverageNormal,
+                                      CORBA::Boolean                useInputElemsOnly,
+                                      CORBA::Boolean                makeGroups,
+                                      CORBA::Short                  dim)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   initData();
 
-  try {
-#ifdef NO_CAS_CATCH
-    OCC_CATCH_SIGNALS;
-#endif
-    TIDSortedElemSet elements, copyElements;
-    arrayToSet(theIDsOfElements, getMeshDS(), elements, theElementType);
+  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+
+  ExtrusionParams params( stepSize, nbOfSteps, dim,
+                          byAverageNormal, useInputElemsOnly, makeGroups );
 
 
-    const SMESH::PointStruct * P = &theStepVector.PS;
-    gp_Vec stepVec( P->x, P->y, P->z );
+  SMDSAbs_ElementType elemType = ( dim == 1 ? SMDSAbs_Edge : SMDSAbs_Face );
+  if ( objects.length() > 0 && !SMESH::DownCast<SMESH_Mesh_i*>( objects[0] ))
+  {
+    SMESH::array_of_ElementType_var elemTypes = objects[0]->GetTypes();
+    if (( elemTypes->length() == 1 ) &&
+        ( elemTypes[0] == SMESH::EDGE || elemTypes[0] == SMESH::FACE ))
+      elemType = ( SMDSAbs_ElementType ) elemTypes[0];
+  }
 
 
-    TIDSortedElemSet* workElements = & elements;
+  TIDSortedElemSet elemsNodes[2];
+  for ( int i = 0, nb = objects.length(); i < nb; ++i )
+    idSourceToSet( objects[i], getMeshDS(), elemsNodes[0], elemType );
 
 
-    SMDSAbs_ElementType aType = SMDSAbs_Face;
-    if (theElementType == SMDSAbs_Node)
-    {
-      aType = SMDSAbs_Edge;
-    }
-    if ( myIsPreviewMode ) {
-      SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
-      getPreviewMesh( aType )->Copy( elements, copyElements, select, avoid );
-      workElements = & copyElements;
-      theMakeGroups = false;
-    }
+  TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
+  SMDSAbs_ElementType previewType = SMDSAbs_Face;
+  if ( myIsPreviewMode )
+  {
+    SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
+    TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
+    tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
+    workElements = & copyElements[0];
 
 
-    TElemOfElemListMap aHystory;
-    ::SMESH_MeshEditor::PGroupIDs groupIds = 
-        getEditor().ExtrusionSweep (*workElements, stepVec, theNbOfSteps, aHystory, theMakeGroups);
+    params.SetNoGroups();
+  }
 
 
-    myMesh->GetMeshDS()->Modified();
+  ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
+  ::SMESH_MeshEditor::PGroupIDs groupIds =
+      getEditor().ExtrusionSweep( workElements, params, aHistory );
 
 
-    return theMakeGroups ? getGroups(groupIds.get()) : 0;
+  SMESH::ListOfGroups * aGroups = makeGroups ? getGroups( groupIds.get()) : 0;
 
 
-  } catch(Standard_Failure) {
-    Handle(Standard_Failure) aFail = Standard_Failure::Caught();
-    INFOS( "SMESH_MeshEditor_i::ExtrusionSweep fails - "<< aFail->GetMessageString() );
+  if (!myIsPreviewMode) {
+    dumpGroupsList(aPythonDump, aGroups);
+    aPythonDump << this << ".ExtrusionByNormal( " << objects
+                << ", " << TVar( stepSize )
+                << ", " << TVar( nbOfSteps )
+                << ", " << byAverageNormal
+                << ", " << useInputElemsOnly
+                << ", " << makeGroups
+                << ", " << dim
+                << " )";
+  }
+  else
+  {
+    getPreviewMesh( previewType )->Remove( SMDSAbs_Volume );
   }
   }
+
+  declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
+
+  return aGroups ? aGroups : new SMESH::ListOfGroups;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
   return 0;
 }
 
 //=======================================================================
   return 0;
 }
 
 //=======================================================================
-//function : ExtrusionSweep
+//function : AdvancedExtrusion
 //purpose  :
 //=======================================================================
 
 //purpose  :
 //=======================================================================
 
-void SMESH_MeshEditor_i::ExtrusionSweep(const SMESH::long_array & theIDsOfElements,
-                                        const SMESH::DirStruct &  theStepVector,
-                                        CORBA::Long               theNbOfSteps)
+SMESH::ListOfGroups*
+SMESH_MeshEditor_i::AdvancedExtrusion(const SMESH::long_array & theIDsOfElements,
+                                      const SMESH::DirStruct &  theStepVector,
+                                      CORBA::Long               theNbOfSteps,
+                                      CORBA::Long               theExtrFlags,
+                                      CORBA::Double             theSewTolerance,
+                                      CORBA::Boolean            theMakeGroups)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  extrusionSweep (theIDsOfElements, theStepVector, theNbOfSteps, false );
-  if (!myIsPreviewMode) {
-    TPythonDump() << this << ".ExtrusionSweep( "
-                  << theIDsOfElements << ", " << theStepVector <<", " << TVar(theNbOfSteps) << " )";
-  }
-}
+  SMESH_TRY;
+  initData();
 
 
-//=======================================================================
-//function : ExtrusionSweep0D
-//purpose  :
-//=======================================================================
+  TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
 
 
-void SMESH_MeshEditor_i::ExtrusionSweep0D(const SMESH::long_array & theIDsOfElements,
-                                          const SMESH::DirStruct &  theStepVector,
-                                          CORBA::Long               theNbOfSteps)
-{
-  extrusionSweep (theIDsOfElements, theStepVector, theNbOfSteps, false, SMDSAbs_Node );
-  if (!myIsPreviewMode) {
-    TPythonDump() << this << ".ExtrusionSweep0D( "
-                  << theIDsOfElements << ", " << theStepVector <<", " << TVar(theNbOfSteps)<< " )";
-  }
-}
+  ExtrusionParams params( theStepVector, theNbOfSteps, theMakeGroups,
+                          theExtrFlags, theSewTolerance );
 
 
-//=======================================================================
-//function : ExtrusionSweepObject
-//purpose  :
-//=======================================================================
+  TIDSortedElemSet elemsNodes[2];
+  arrayToSet( theIDsOfElements, getMeshDS(), elemsNodes[0] );
 
 
-void SMESH_MeshEditor_i::ExtrusionSweepObject(SMESH::SMESH_IDSource_ptr theObject,
-                                              const SMESH::DirStruct &  theStepVector,
-                                              CORBA::Long               theNbOfSteps)
-{
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  extrusionSweep (anElementsId, theStepVector, theNbOfSteps, false );
-  if (!myIsPreviewMode) {
-    TPythonDump() << this << ".ExtrusionSweepObject( "
-                  << theObject << ", " << theStepVector << ", " << theNbOfSteps << " )";
-  }
-}
+  ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
+  ::SMESH_MeshEditor::PGroupIDs groupIds =
+      getEditor().ExtrusionSweep( elemsNodes, params, aHistory );
 
 
-//=======================================================================
-//function : ExtrusionSweepObject0D
-//purpose  :
-//=======================================================================
+  SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0;
+
+  declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
 
 
-void SMESH_MeshEditor_i::ExtrusionSweepObject0D(SMESH::SMESH_IDSource_ptr theObject,
-                                                const SMESH::DirStruct &  theStepVector,
-                                                CORBA::Long               theNbOfSteps)
-{
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  extrusionSweep (anElementsId, theStepVector, theNbOfSteps, false, SMDSAbs_Node );
   if ( !myIsPreviewMode ) {
   if ( !myIsPreviewMode ) {
-    TPythonDump() << this << ".ExtrusionSweepObject0D( "
-                  << theObject << ", " << theStepVector << ", " << TVar( theNbOfSteps ) << " )";
+    dumpGroupsList(aPythonDump, aGroups);
+    aPythonDump << this << ".AdvancedExtrusion( "
+                << theIDsOfElements << ", "
+                << theStepVector << ", "
+                << theNbOfSteps << ", "
+                << theExtrFlags << ", "
+                << theSewTolerance << ", "
+                << theMakeGroups << " )";
+  }
+  else
+  {
+    getPreviewMesh()->Remove( SMDSAbs_Volume );
   }
   }
-}
 
 
-//=======================================================================
-//function : ExtrusionSweepObject1D
-//purpose  :
-//=======================================================================
+  return aGroups ? aGroups : new SMESH::ListOfGroups;
 
 
-void SMESH_MeshEditor_i::ExtrusionSweepObject1D(SMESH::SMESH_IDSource_ptr theObject,
-                                                const SMESH::DirStruct &  theStepVector,
-                                                CORBA::Long               theNbOfSteps)
-{
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  extrusionSweep (anElementsId, theStepVector, theNbOfSteps, false, SMDSAbs_Edge );
-  if ( !myIsPreviewMode ) {
-    TPythonDump() << this << ".ExtrusionSweepObject1D( "
-                  << theObject << ", " << theStepVector << ", " << TVar( theNbOfSteps ) << " )";
-  }
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 }
 
-//=======================================================================
-//function : ExtrusionSweepObject2D
-//purpose  :
-//=======================================================================
+//================================================================================
+/*!
+ * \brief Convert extrusion error to IDL enum
+ */
+//================================================================================
 
 
-void SMESH_MeshEditor_i::ExtrusionSweepObject2D(SMESH::SMESH_IDSource_ptr theObject,
-                                                const SMESH::DirStruct &  theStepVector,
-                                                CORBA::Long               theNbOfSteps)
+namespace
 {
 {
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  extrusionSweep (anElementsId, theStepVector, theNbOfSteps, false, SMDSAbs_Face );
-  if ( !myIsPreviewMode ) {
-    TPythonDump() << this << ".ExtrusionSweepObject2D( "
-                  << theObject << ", " << theStepVector << ", " << TVar( theNbOfSteps ) << " )";
+#define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
+
+  SMESH::SMESH_MeshEditor::Extrusion_Error convExtrError( ::SMESH_MeshEditor::Extrusion_Error e )
+  {
+    switch ( e ) {
+      RETCASE( EXTR_OK );
+      RETCASE( EXTR_NO_ELEMENTS );
+      RETCASE( EXTR_PATH_NOT_EDGE );
+      RETCASE( EXTR_BAD_PATH_SHAPE );
+      RETCASE( EXTR_BAD_STARTING_NODE );
+      RETCASE( EXTR_BAD_ANGLES_NUMBER );
+      RETCASE( EXTR_CANT_GET_TANGENT );
+    }
+    return SMESH::SMESH_MeshEditor::EXTR_OK;
   }
 }
 
 //=======================================================================
   }
 }
 
 //=======================================================================
-//function : ExtrusionSweepMakeGroups
+//function : extrusionAlongPath
 //purpose  :
 //=======================================================================
 //purpose  :
 //=======================================================================
-
 SMESH::ListOfGroups*
 SMESH::ListOfGroups*
-SMESH_MeshEditor_i::ExtrusionSweepMakeGroups(const SMESH::long_array& theIDsOfElements,
-                                             const SMESH::DirStruct&  theStepVector,
-                                             CORBA::Long              theNbOfSteps)
+SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & theNodes,
+                                              const SMESH::ListOfIDSources & theEdges,
+                                              const SMESH::ListOfIDSources & theFaces,
+                                              SMESH::SMESH_IDSource_ptr      thePathObject,
+                                              GEOM::GEOM_Object_ptr          thePathShape,
+                                              CORBA::Long                    theNodeStart,
+                                              CORBA::Boolean                 theHasAngles,
+                                              const SMESH::double_array &    theAngles,
+                                              CORBA::Boolean                 theAnglesVariation,
+                                              CORBA::Boolean                 theHasRefPoint,
+                                              const SMESH::PointStruct &     theRefPoint,
+                                              bool                           theMakeGroups,
+                                              const SMESH::double_array &    theScaleFactors,
+                                              CORBA::Boolean                 theScalesVariation,
+                                              SMESH::SMESH_MeshEditor::Extrusion_Error& theError)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+  SMESH_TRY;
+  initData();
 
 
-  SMESH::ListOfGroups* aGroups = extrusionSweep(theIDsOfElements, theStepVector, theNbOfSteps, true);
+  SMESH::ListOfGroups_var aGroups = new SMESH::ListOfGroups;
 
 
-  if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".ExtrusionSweepMakeGroups( " << theIDsOfElements
-                << ", " << theStepVector <<", " << TVar( theNbOfSteps ) << " )";
-  }
-  return aGroups;
-}
+  theError = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE;
+  if ( thePathObject->_is_nil() )
+    return aGroups._retn();
 
 
-//=======================================================================
-//function : ExtrusionSweepMakeGroups0D
-//purpose  :
-//=======================================================================
 
 
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::ExtrusionSweepMakeGroups0D(const SMESH::long_array& theIDsOfElements,
-                                               const SMESH::DirStruct&  theStepVector,
-                                               CORBA::Long              theNbOfSteps)
-{
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+  SMDS_ElemIteratorPtr pathEdgesIterator;
+
+  SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathObject );
+  if ( !CORBA::is_nil( thePathShape ) && aMeshImp )
+  {
+    // get a sub-mesh of thePathShape
+    TopoDS_Shape     aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
+    SMESH_subMesh* aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
+    if ( !aSubMesh )
+      return aGroups._retn();
 
 
-  SMESH::ListOfGroups* aGroups = extrusionSweep(theIDsOfElements, theStepVector, theNbOfSteps, true,SMDSAbs_Node);
+    if ( !aSubMesh->GetSubMeshDS() )
+    {
+      SMESHDS_Mesh * meshDS = aMeshImp->GetImpl().GetMeshDS();
+      meshDS->AddCompoundSubmesh( aShape, TopAbs_EDGE );
+      if ( !aSubMesh->GetSubMeshDS() )
+        return aGroups._retn();
+    }
+    theError = SMESH::SMESH_MeshEditor::EXTR_PATH_NOT_EDGE;
+    pathEdgesIterator = aSubMesh->GetSubMeshDS()->GetElements();
+    if ( !pathEdgesIterator->more() ||
+         pathEdgesIterator->next()->GetType() != SMDSAbs_Edge )
+      return aGroups._retn();
 
 
-  if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".ExtrusionSweepMakeGroups0D( " << theIDsOfElements
-                << ", " << theStepVector <<", " << TVar( theNbOfSteps ) << " )";
+    pathEdgesIterator = aSubMesh->GetSubMeshDS()->GetElements();
+  }
+  else
+  {
+    theError = SMESH::SMESH_MeshEditor::EXTR_PATH_NOT_EDGE;
+    prepareIdSource( thePathObject );
+    pathEdgesIterator = SMESH_Mesh_i::GetElements( thePathObject, SMESH::EDGE );
+    if ( !pathEdgesIterator || !pathEdgesIterator->more() )
+      return aGroups._retn();
   }
   }
-  return aGroups;
-}
 
 
-//=======================================================================
-//function : ExtrusionSweepObjectMakeGroups
-//purpose  :
-//=======================================================================
+  if ( !aMeshImp )
+  {
+    SMESH::SMESH_Mesh_var pathMesh = thePathObject->GetMesh();
+    aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( pathMesh );
+  }
 
 
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::ExtrusionSweepObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
-                                                   const SMESH::DirStruct&   theStepVector,
-                                                   CORBA::Long               theNbOfSteps)
-{
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
 
 
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  SMESH::ListOfGroups * aGroups = extrusionSweep(anElementsId, theStepVector, theNbOfSteps, true);
+  theError = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
+  const SMDS_MeshNode* nodeStart = aMeshImp->GetImpl().GetMeshDS()->FindNode( theNodeStart );
+  if ( !nodeStart )
+    return aGroups._retn();
 
 
-  if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".ExtrusionSweepObjectMakeGroups( " << theObject
-                << ", " << theStepVector << ", " << theNbOfSteps << " )";
+
+  TIDSortedElemSet elemsNodes[2];
+  for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
+    if ( SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE ))
+      while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
   }
   }
-  return aGroups;
-}
+  for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
+    idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
+  for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
+    idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
 
 
-//=======================================================================
-//function : ExtrusionSweepObject0DMakeGroups
-//purpose  :
-//=======================================================================
+  list<double> angles = ExtrusionParams::toList( theAngles );
+  list<double> scales = ExtrusionParams::toList( theScaleFactors );
 
 
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::ExtrusionSweepObject0DMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
-                                                     const SMESH::DirStruct&   theStepVector,
-                                                     CORBA::Long               theNbOfSteps)
-{
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+  gp_Pnt refPnt( theRefPoint.x, theRefPoint.y, theRefPoint.z );
+  const gp_Pnt *refPntPtr = theHasRefPoint ? &refPnt : 0;
 
 
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  SMESH::ListOfGroups * aGroups = extrusionSweep(anElementsId, theStepVector,
-                                                 theNbOfSteps, true, SMDSAbs_Node);
-  if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".ExtrusionSweepObject0DMakeGroups( " << theObject
-                << ", " << theStepVector << ", " << TVar( theNbOfSteps ) << " )";
-  }
-  return aGroups;
-}
+  int nbOldGroups = myMesh->NbGroup();
 
 
-//=======================================================================
-//function : ExtrusionSweepObject1DMakeGroups
-//purpose  :
-//=======================================================================
+  TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
+  if ( myIsPreviewMode )
+  {
+    SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
+    TPreviewMesh * tmpMesh = getPreviewMesh();
+    tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
+    tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
+    workElements = & copyElements[0];
+    theMakeGroups = false;
+  }
 
 
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::ExtrusionSweepObject1DMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
-                                                     const SMESH::DirStruct&   theStepVector,
-                                                     CORBA::Long               theNbOfSteps)
-{
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+  ::SMESH_MeshEditor::Extrusion_Error error =
+      getEditor().ExtrusionAlongTrack( workElements,
+                                       &(aMeshImp->GetImpl()), pathEdgesIterator, nodeStart,
+                                       angles, theAnglesVariation,
+                                       scales, theScalesVariation,
+                                       refPntPtr, theMakeGroups );
 
 
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  SMESH::ListOfGroups * aGroups = extrusionSweep(anElementsId, theStepVector,
-                                                 theNbOfSteps, true, SMDSAbs_Edge);
-  if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".ExtrusionSweepObject1DMakeGroups( " << theObject
-                << ", " << theStepVector << ", " << TVar( theNbOfSteps ) << " )";
+  declareMeshModified( /*isReComputeSafe=*/true );
+  theError = convExtrError( error );
+
+  TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
+  if ( theMakeGroups ) {
+    list<int> groupIDs = myMesh->GetGroupIds();
+    list<int>::iterator newBegin = groupIDs.begin();
+    std::advance( newBegin, nbOldGroups ); // skip old groups
+    groupIDs.erase( groupIDs.begin(), newBegin );
+    aGroups = getGroups( & groupIDs );
+    if ( ! &aGroups.in() ) aGroups = new SMESH::ListOfGroups;
   }
   }
-  return aGroups;
+
+  if ( !myIsPreviewMode ) {
+    if ( aGroups->length() > 0 ) aPythonDump << "(" << aGroups << ", error) = ";
+    else                         aPythonDump << "(_noGroups, error) = ";
+    aPythonDump << this << ".ExtrusionAlongPathObjects( "
+                << theNodes            << ", "
+                << theEdges            << ", "
+                << theFaces            << ", "
+                << thePathObject       << ", "
+                << thePathShape        << ", "
+                << theNodeStart        << ", "
+                << theHasAngles        << ", "
+                << TVar( theAngles )   << ", "
+                << theAnglesVariation  << ", "
+                << theHasRefPoint      << ", "
+                << "SMESH.PointStruct( "
+                << TVar( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
+                << TVar( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
+                << TVar( theHasRefPoint ? theRefPoint.z : 0 ) << " ), "
+                << theMakeGroups           << ", "
+                << TVar( theScaleFactors ) << ", "
+                << theScalesVariation      << " )";
+  }
+  else
+  {
+    getPreviewMesh()->Remove( SMDSAbs_Volume );
+  }
+
+  return aGroups._retn();
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 }
 
-//=======================================================================
-//function : ExtrusionSweepObject2DMakeGroups
-//purpose  :
-//=======================================================================
+//================================================================================
+/*!
+ * \brief Compute rotation angles for ExtrusionAlongPath as linear variation
+ * of given angles along path steps
+ * \param PathMesh mesh containing a 1D sub-mesh on the edge, along
+ *                which proceeds the extrusion
+ * \param PathShape is shape(edge); as the mesh can be complex, the edge
+ *                 is used to define the sub-mesh for the path
+ */
+//================================================================================
 
 
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::ExtrusionSweepObject2DMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
-                                                     const SMESH::DirStruct&   theStepVector,
-                                                     CORBA::Long               theNbOfSteps)
+SMESH::double_array*
+SMESH_MeshEditor_i::LinearAnglesVariation(SMESH::SMESH_Mesh_ptr       thePathMesh,
+                                          GEOM::GEOM_Object_ptr       thePathShape,
+                                          const SMESH::double_array & theAngles)
 {
 {
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+  SMESH::double_array_var aResult = new SMESH::double_array();
+  int nbAngles = theAngles.length();
+  if ( nbAngles > 0 && !thePathMesh->_is_nil() && !thePathShape->_is_nil() )
+  {
+    SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
+    TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
+    SMESH_subMesh* aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
+    if ( !aSubMesh || !aSubMesh->GetSubMeshDS())
+      return aResult._retn();
+    int nbSteps = aSubMesh->GetSubMeshDS()->NbElements();
+    if ( nbSteps == nbAngles )
+    {
+      aResult.inout() = theAngles;
+    }
+    else
+    {
+      aResult->length( nbSteps );
+      double rAn2St = double( nbAngles ) / double( nbSteps );
+      double angPrev = 0, angle;
+      for ( int iSt = 0; iSt < nbSteps; ++iSt )
+      {
+        double angCur = rAn2St * ( iSt+1 );
+        double angCurFloor  = floor( angCur );
+        double angPrevFloor = floor( angPrev );
+        if ( angPrevFloor == angCurFloor )
+          angle = rAn2St * theAngles[ int( angCurFloor ) ];
+        else
+        {
+          int iP = int( angPrevFloor );
+          double angPrevCeil = ceil(angPrev);
+          angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
 
 
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  SMESH::ListOfGroups * aGroups = extrusionSweep(anElementsId, theStepVector,
-                                                 theNbOfSteps, true, SMDSAbs_Face);
-  if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".ExtrusionSweepObject2DMakeGroups( " << theObject
-                << ", " << theStepVector << ", " << TVar( theNbOfSteps ) << " )";
+          int iC = int( angCurFloor );
+          if ( iC < nbAngles )
+            angle += ( angCur - angCurFloor ) * theAngles[ iC ];
+
+          iP = int( angPrevCeil );
+          while ( iC-- > iP )
+            angle += theAngles[ iC ];
+        }
+        aResult[ iSt ] = angle;
+        angPrev = angCur;
+      }
+    }
   }
   }
-  return aGroups;
-}
+  // Update Python script
+  TPythonDump() << "rotAngles = " << theAngles;
+  TPythonDump() << "rotAngles = " << this << ".LinearAnglesVariation( "
+                << thePathMesh  << ", "
+                << thePathShape << ", "
+                << "rotAngles )";
 
 
+  return aResult._retn();
+}
 
 //=======================================================================
 
 //=======================================================================
-//function : advancedExtrusion
+//function : mirror
 //purpose  :
 //=======================================================================
 
 SMESH::ListOfGroups*
 //purpose  :
 //=======================================================================
 
 SMESH::ListOfGroups*
-SMESH_MeshEditor_i::advancedExtrusion(const SMESH::long_array & theIDsOfElements,
-                                      const SMESH::DirStruct &  theStepVector,
-                                      CORBA::Long               theNbOfSteps,
-                                      CORBA::Long               theExtrFlags,
-                                      CORBA::Double             theSewTolerance,
-                                      const bool                theMakeGroups)
+SMESH_MeshEditor_i::mirror(TIDSortedElemSet &                  theElements,
+                           const SMESH::AxisStruct &           theAxis,
+                           SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
+                           CORBA::Boolean                      theCopy,
+                           bool                                theMakeGroups,
+                           ::SMESH_Mesh*                       theTargetMesh)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   initData();
 
-  TIDSortedElemSet elements;
-  arrayToSet(theIDsOfElements, getMeshDS(), elements);
+  gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
+  gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
+
+  if ( theTargetMesh )
+    theCopy = false;
+
+  gp_Trsf aTrsf;
+  switch ( theMirrorType ) {
+  case  SMESH::SMESH_MeshEditor::POINT:
+    aTrsf.SetMirror( P );
+    break;
+  case  SMESH::SMESH_MeshEditor::AXIS:
+    aTrsf.SetMirror( gp_Ax1( P, V ));
+    break;
+  default:
+    aTrsf.SetMirror( gp_Ax2( P, V ));
+  }
+
+  TIDSortedElemSet  copyElements;
+  TIDSortedElemSet* workElements = & theElements;
 
 
-  const SMESH::PointStruct * P = &theStepVector.PS;
-  gp_Vec stepVec( P->x, P->y, P->z );
+  if ( myIsPreviewMode )
+  {
+    TPreviewMesh * tmpMesh = getPreviewMesh();
+    tmpMesh->Copy( theElements, copyElements);
+    if ( !theCopy && !theTargetMesh )
+    {
+      TIDSortedElemSet elemsAround, elemsAroundCopy;
+      getElementsAround( theElements, getMeshDS(), elemsAround );
+      tmpMesh->Copy( elemsAround, elemsAroundCopy);
+    }
+    workElements = & copyElements;
+    theMakeGroups = false;
+  }
 
 
-  TElemOfElemListMap aHystory;
   ::SMESH_MeshEditor::PGroupIDs groupIds =
   ::SMESH_MeshEditor::PGroupIDs groupIds =
-      getEditor().ExtrusionSweep (elements, stepVec, theNbOfSteps, aHystory,
-                                  theMakeGroups, theExtrFlags, theSewTolerance);
+      getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
+
+  if ( !myIsPreviewMode )
+  {
+    if ( theTargetMesh )
+      theTargetMesh->GetMeshDS()->Modified();
+    else
+      declareMeshModified( /*isReComputeSafe=*/false );
+  }
 
   return theMakeGroups ? getGroups(groupIds.get()) : 0;
 
   return theMakeGroups ? getGroups(groupIds.get()) : 0;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : AdvancedExtrusion
+//function : Mirror
 //purpose  :
 //=======================================================================
 
 //purpose  :
 //=======================================================================
 
-void SMESH_MeshEditor_i::AdvancedExtrusion(const SMESH::long_array & theIDsOfElements,
-                                           const SMESH::DirStruct &  theStepVector,
-                                           CORBA::Long               theNbOfSteps,
-                                           CORBA::Long               theExtrFlags,
-                                           CORBA::Double             theSewTolerance)
+void SMESH_MeshEditor_i::Mirror(const SMESH::long_array &           theIDsOfElements,
+                                const SMESH::AxisStruct &           theAxis,
+                                SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
+                                CORBA::Boolean                      theCopy)
+  throw (SALOME::SALOME_Exception)
 {
   if ( !myIsPreviewMode ) {
 {
   if ( !myIsPreviewMode ) {
-    TPythonDump() << "stepVector = " << theStepVector;
-    TPythonDump() << this << ".AdvancedExtrusion("
-                  << theIDsOfElements
-                  << ", stepVector, "
-                  << theNbOfSteps << ","
-                  << theExtrFlags << ", "
-                  << theSewTolerance <<  " )";
+    TPythonDump() << this << ".Mirror( "
+                  << theIDsOfElements              << ", "
+                  << theAxis                       << ", "
+                  << mirrorTypeName(theMirrorType) << ", "
+                  << theCopy                       << " )";
+  }
+  if ( theIDsOfElements.length() > 0 )
+  {
+    TIDSortedElemSet elements;
+    arrayToSet(theIDsOfElements, getMeshDS(), elements);
+    mirror(elements, theAxis, theMirrorType, theCopy, false);
   }
   }
-  advancedExtrusion( theIDsOfElements,
-                     theStepVector,
-                     theNbOfSteps,
-                     theExtrFlags,
-                     theSewTolerance,
-                     false);
 }
 
 }
 
+
 //=======================================================================
 //=======================================================================
-//function : AdvancedExtrusionMakeGroups
+//function : MirrorObject
 //purpose  :
 //=======================================================================
 //purpose  :
 //=======================================================================
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::AdvancedExtrusionMakeGroups(const SMESH::long_array& theIDsOfElements,
-                                                const SMESH::DirStruct&  theStepVector,
-                                                CORBA::Long              theNbOfSteps,
-                                                CORBA::Long              theExtrFlags,
-                                                CORBA::Double            theSewTolerance)
+
+void SMESH_MeshEditor_i::MirrorObject(SMESH::SMESH_IDSource_ptr           theObject,
+                                      const SMESH::AxisStruct &           theAxis,
+                                      SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
+                                      CORBA::Boolean                      theCopy)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  if (!myIsPreviewMode) {
-    TPythonDump() << "stepVector = " << theStepVector;
+  if ( !myIsPreviewMode ) {
+    TPythonDump() << this << ".MirrorObject( "
+                  << theObject                     << ", "
+                  << theAxis                       << ", "
+                  << mirrorTypeName(theMirrorType) << ", "
+                  << theCopy                       << " )";
   }
   }
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+  TIDSortedElemSet elements;
 
 
-  SMESH::ListOfGroups * aGroups = advancedExtrusion( theIDsOfElements,
-                                                     theStepVector,
-                                                     theNbOfSteps,
-                                                     theExtrFlags,
-                                                     theSewTolerance,
-                                                     true);
+  bool emptyIfIsMesh = myIsPreviewMode ? false : true;
 
 
-  if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".AdvancedExtrusionMakeGroups("
-                << theIDsOfElements
-                << ", stepVector, "
-                << theNbOfSteps << ","
-                << theExtrFlags << ", "
-                << theSewTolerance <<  " )";
-  }
-  return aGroups;
+  if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
+    mirror(elements, theAxis, theMirrorType, theCopy, false);
 }
 
 }
 
+//=======================================================================
+//function : MirrorMakeGroups
+//purpose  :
+//=======================================================================
 
 
-//================================================================================
-/*!
- * \brief Convert extrusion error to IDL enum
- */
-//================================================================================
-
-#define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
-
-static SMESH::SMESH_MeshEditor::Extrusion_Error convExtrError( const::SMESH_MeshEditor::Extrusion_Error e )
+SMESH::ListOfGroups*
+SMESH_MeshEditor_i::MirrorMakeGroups(const SMESH::long_array&            theIDsOfElements,
+                                     const SMESH::AxisStruct&            theMirror,
+                                     SMESH::SMESH_MeshEditor::MirrorType theMirrorType)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  switch ( e ) {
-    RETCASE( EXTR_OK );
-    RETCASE( EXTR_NO_ELEMENTS );
-    RETCASE( EXTR_PATH_NOT_EDGE );
-    RETCASE( EXTR_BAD_PATH_SHAPE );
-    RETCASE( EXTR_BAD_STARTING_NODE );
-    RETCASE( EXTR_BAD_ANGLES_NUMBER );
-    RETCASE( EXTR_CANT_GET_TANGENT );
+  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+
+  SMESH::ListOfGroups * aGroups = 0;
+  if ( theIDsOfElements.length() > 0 )
+  {
+    TIDSortedElemSet elements;
+    arrayToSet(theIDsOfElements, getMeshDS(), elements);
+    aGroups = mirror(elements, theMirror, theMirrorType, true, true);
+  }
+  if (!myIsPreviewMode) {
+    dumpGroupsList(aPythonDump, aGroups);
+    aPythonDump << this << ".MirrorMakeGroups( "
+                << theIDsOfElements              << ", "
+                << theMirror                     << ", "
+                << mirrorTypeName(theMirrorType) << " )";
   }
   }
-  return SMESH::SMESH_MeshEditor::EXTR_OK;
+  return aGroups;
 }
 
 }
 
-
 //=======================================================================
 //=======================================================================
-//function : extrusionAlongPath
+//function : MirrorObjectMakeGroups
 //purpose  :
 //=======================================================================
 //purpose  :
 //=======================================================================
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::extrusionAlongPath(const SMESH::long_array &   theIDsOfElements,
-                                       SMESH::SMESH_Mesh_ptr       thePathMesh,
-                                       GEOM::GEOM_Object_ptr       thePathShape,
-                                       CORBA::Long                 theNodeStart,
-                                       CORBA::Boolean              theHasAngles,
-                                       const SMESH::double_array & theAngles,
-                                       CORBA::Boolean              theHasRefPoint,
-                                       const SMESH::PointStruct &  theRefPoint,
-                                       const bool                  theMakeGroups,
-                                       SMESH::SMESH_MeshEditor::Extrusion_Error & theError,
-                                       const SMDSAbs_ElementType   theElementType)
-{
-  MESSAGE("extrusionAlongPath");
-  initData();
-
-  if ( thePathMesh->_is_nil() || thePathShape->_is_nil() ) {
-    theError = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE;
-    return 0;
-  }
-  SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
 
 
-  TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
-  SMESH_subMesh* aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
+SMESH::ListOfGroups*
+SMESH_MeshEditor_i::MirrorObjectMakeGroups(SMESH::SMESH_IDSource_ptr           theObject,
+                                           const SMESH::AxisStruct&            theMirror,
+                                           SMESH::SMESH_MeshEditor::MirrorType theMirrorType)
+  throw (SALOME::SALOME_Exception)
+{
+  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
 
 
-  if ( !aSubMesh || !aSubMesh->GetSubMeshDS()) {
-    theError = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE;
-    return 0;
-  }
+  SMESH::ListOfGroups * aGroups = 0;
+  TIDSortedElemSet elements;
+  if ( idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
+    aGroups = mirror(elements, theMirror, theMirrorType, true, true);
 
 
-  SMDS_MeshNode* nodeStart = (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(theNodeStart);
-  if ( !nodeStart ) {
-    theError = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
-    return 0;
+  if (!myIsPreviewMode)
+  {
+    dumpGroupsList(aPythonDump,aGroups);
+    aPythonDump << this << ".MirrorObjectMakeGroups( "
+                << theObject                     << ", "
+                << theMirror                     << ", "
+                << mirrorTypeName(theMirrorType) << " )";
   }
   }
+  return aGroups;
+}
 
 
-  TIDSortedElemSet elements;
-  arrayToSet(theIDsOfElements, getMeshDS(), elements, theElementType);
+//=======================================================================
+//function : MirrorMakeMesh
+//purpose  :
+//=======================================================================
+
+SMESH::SMESH_Mesh_ptr
+SMESH_MeshEditor_i::MirrorMakeMesh(const SMESH::long_array&            theIDsOfElements,
+                                   const SMESH::AxisStruct&            theMirror,
+                                   SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
+                                   CORBA::Boolean                      theCopyGroups,
+                                   const char*                         theMeshName)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH_Mesh_i* mesh_i;
+  SMESH::SMESH_Mesh_var mesh;
+  { // open new scope to dump "MakeMesh" command
+    // and then "GetGroups" using SMESH_Mesh::GetGroups()
+
+    TPythonDump pydump; // to prevent dump at mesh creation
+
+    mesh = makeMesh( theMeshName );
+    mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
+    if (mesh_i && theIDsOfElements.length() > 0 )
+    {
+      TIDSortedElemSet elements;
+      arrayToSet(theIDsOfElements, getMeshDS(), elements);
+      mirror(elements, theMirror, theMirrorType,
+             false, theCopyGroups, & mesh_i->GetImpl());
+      mesh_i->CreateGroupServants();
+    }
 
 
-  list<double> angles;
-  for (int i = 0; i < theAngles.length(); i++) {
-    angles.push_back( theAngles[i] );
+    if (!myIsPreviewMode) {
+      pydump << mesh << " = " << this << ".MirrorMakeMesh( "
+             << theIDsOfElements              << ", "
+             << theMirror                     << ", "
+             << mirrorTypeName(theMirrorType) << ", "
+             << theCopyGroups                 << ", '"
+             << theMeshName                   << "' )";
+    }
   }
 
   }
 
-  gp_Pnt refPnt( theRefPoint.x, theRefPoint.y, theRefPoint.z );
+  //dump "GetGroups"
+  if (!myIsPreviewMode && mesh_i)
+    mesh_i->GetGroups();
 
 
-  int nbOldGroups = myMesh->NbGroup();
+  return mesh._retn();
+}
 
 
-  ::SMESH_MeshEditor::Extrusion_Error error =
-      getEditor().ExtrusionAlongTrack( elements, aSubMesh, nodeStart,
-                                    theHasAngles, angles, false,
-                                    theHasRefPoint, refPnt, theMakeGroups );
-  myMesh->GetMeshDS()->Modified();
-  theError = convExtrError( error );
+//=======================================================================
+//function : MirrorObjectMakeMesh
+//purpose  :
+//=======================================================================
 
 
-  if ( theMakeGroups ) {
-    list<int> groupIDs = myMesh->GetGroupIds();
-    list<int>::iterator newBegin = groupIDs.begin();
-    std::advance( newBegin, nbOldGroups ); // skip old groups
-    groupIDs.erase( groupIDs.begin(), newBegin );
-    return getGroups( & groupIDs );
+SMESH::SMESH_Mesh_ptr
+SMESH_MeshEditor_i::MirrorObjectMakeMesh(SMESH::SMESH_IDSource_ptr           theObject,
+                                         const SMESH::AxisStruct&            theMirror,
+                                         SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
+                                         CORBA::Boolean                      theCopyGroups,
+                                         const char*                         theMeshName)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH_Mesh_i* mesh_i;
+  SMESH::SMESH_Mesh_var mesh;
+  { // open new scope to dump "MakeMesh" command
+    // and then "GetGroups" using SMESH_Mesh::GetGroups()
+
+    TPythonDump pydump; // to prevent dump at mesh creation
+
+    mesh = makeMesh( theMeshName );
+    mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
+    TIDSortedElemSet elements;
+    if ( mesh_i &&
+         idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
+    {
+      mirror(elements, theMirror, theMirrorType,
+             false, theCopyGroups, & mesh_i->GetImpl());
+      mesh_i->CreateGroupServants();
+    }
+    if (!myIsPreviewMode) {
+      pydump << mesh << " = " << this << ".MirrorObjectMakeMesh( "
+             << theObject                     << ", "
+             << theMirror                     << ", "
+             << mirrorTypeName(theMirrorType) << ", "
+             << theCopyGroups                 << ", '"
+             << theMeshName                   << "' )";
+    }
   }
   }
-  return 0;
-}
 
 
+  //dump "GetGroups"
+  if (!myIsPreviewMode && mesh_i)
+    mesh_i->GetGroups();
+
+  return mesh._retn();
+}
 
 //=======================================================================
 
 //=======================================================================
-//function : extrusionAlongPathX
+//function : translate
 //purpose  :
 //=======================================================================
 //purpose  :
 //=======================================================================
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::extrusionAlongPathX(const SMESH::long_array &  IDsOfElements,
-                                        SMESH::SMESH_IDSource_ptr  Path,
-                                        CORBA::Long                NodeStart,
-                                        CORBA::Boolean             HasAngles,
-                                        const SMESH::double_array& Angles,
-                                        CORBA::Boolean             LinearVariation,
-                                        CORBA::Boolean             HasRefPoint,
-                                        const SMESH::PointStruct&  RefPoint,
-                                        bool                       MakeGroups,
-                                        const SMDSAbs_ElementType  ElementType,
-                                        SMESH::SMESH_MeshEditor::Extrusion_Error & Error)
-{
-  SMESH::ListOfGroups* EmptyGr = new SMESH::ListOfGroups;
 
 
+SMESH::ListOfGroups*
+SMESH_MeshEditor_i::translate(TIDSortedElemSet        & theElements,
+                              const SMESH::DirStruct &  theVector,
+                              CORBA::Boolean            theCopy,
+                              bool                      theMakeGroups,
+                              ::SMESH_Mesh*             theTargetMesh)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH_TRY;
   initData();
 
   initData();
 
-  list<double> angles;
-  for (int i = 0; i < Angles.length(); i++) {
-    angles.push_back( Angles[i] );
-  }
-  gp_Pnt refPnt( RefPoint.x, RefPoint.y, RefPoint.z );
-  int nbOldGroups = myMesh->NbGroup();
-
-  if ( Path->_is_nil() ) {
-    Error = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE;
-    return EmptyGr;
-  }
+  if ( theTargetMesh )
+    theCopy = false;
 
 
-  TIDSortedElemSet elements, copyElements;
-  arrayToSet(IDsOfElements, getMeshDS(), elements, ElementType);
+  gp_Trsf aTrsf;
+  const SMESH::PointStruct * P = &theVector.PS;
+  aTrsf.SetTranslation( gp_Vec( P->x, P->y, P->z ));
 
 
-  TIDSortedElemSet* workElements = &elements;
+  TIDSortedElemSet  copyElements;
+  TIDSortedElemSet* workElements = &theElements;
 
   if ( myIsPreviewMode )
   {
 
   if ( myIsPreviewMode )
   {
-    SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
-    getPreviewMesh( SMDSAbs_Face )->Copy( elements, copyElements, select, avoid );
+    TPreviewMesh * tmpMesh = getPreviewMesh();
+    tmpMesh->Copy( theElements, copyElements);
+    if ( !theCopy && !theTargetMesh )
+    {
+      TIDSortedElemSet elemsAround, elemsAroundCopy;
+      getElementsAround( theElements, getMeshDS(), elemsAround );
+      tmpMesh->Copy( elemsAround, elemsAroundCopy);
+    }
     workElements = & copyElements;
     workElements = & copyElements;
-    MakeGroups = false;
+    theMakeGroups = false;
   }
 
   }
 
-  ::SMESH_MeshEditor::Extrusion_Error error;
+  ::SMESH_MeshEditor::PGroupIDs groupIds =
+      getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
 
 
-  if ( SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( Path ))
-  {
-    // path as mesh
-    SMDS_MeshNode* aNodeStart =
-      (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(NodeStart);
-    if ( !aNodeStart ) {
-      Error = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
-      return EmptyGr;
-    }
-    error = getEditor().ExtrusionAlongTrack( *workElements, &(aMeshImp->GetImpl()), aNodeStart,
-                                             HasAngles, angles, LinearVariation,
-                                             HasRefPoint, refPnt, MakeGroups );
-    myMesh->GetMeshDS()->Modified();
-  }
-  else if ( SMESH_subMesh_i* aSubMeshImp = SMESH::DownCast<SMESH_subMesh_i*>( Path ))
-  {
-    // path as submesh
-    SMESH::SMESH_Mesh_ptr aPathMesh = aSubMeshImp->GetFather();
-    aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( aPathMesh );
-    SMDS_MeshNode* aNodeStart =
-      (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(NodeStart);
-    if ( !aNodeStart ) {
-      Error = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
-      return EmptyGr;
-    }
-    SMESH_subMesh* aSubMesh =
-      aMeshImp->GetImpl().GetSubMeshContaining(aSubMeshImp->GetId());
-    error = getEditor().ExtrusionAlongTrack( *workElements, aSubMesh, aNodeStart,
-                                             HasAngles, angles, LinearVariation,
-                                             HasRefPoint, refPnt, MakeGroups );
-    myMesh->GetMeshDS()->Modified();
-  }
-  else if ( SMESH::DownCast<SMESH_Group_i*>( Path ))
-  {
-    // path as group of 1D elements
-    // ????????
-  }
-  else
+  if ( !myIsPreviewMode )
   {
   {
-    // invalid path
-    Error = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE;
-    return EmptyGr;
+    if ( theTargetMesh )
+      theTargetMesh->GetMeshDS()->Modified();
+    else
+      declareMeshModified( /*isReComputeSafe=*/false );
   }
 
   }
 
-  Error = convExtrError( error );
+  return theMakeGroups ? getGroups(groupIds.get()) : 0;
 
 
-  if ( MakeGroups ) {
-    list<int> groupIDs = myMesh->GetGroupIds();
-    list<int>::iterator newBegin = groupIDs.begin();
-    std::advance( newBegin, nbOldGroups ); // skip old groups
-    groupIDs.erase( groupIDs.begin(), newBegin );
-    return getGroups( & groupIDs );
-  }
-  return EmptyGr;
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 }
 
-
-//=======================================================================
-//function : ExtrusionAlongPath
-//purpose  :
 //=======================================================================
 //=======================================================================
-SMESH::SMESH_MeshEditor::Extrusion_Error
-SMESH_MeshEditor_i::ExtrusionAlongPath(const SMESH::long_array &   theIDsOfElements,
-                                       SMESH::SMESH_Mesh_ptr       thePathMesh,
-                                       GEOM::GEOM_Object_ptr       thePathShape,
-                                       CORBA::Long                 theNodeStart,
-                                       CORBA::Boolean              theHasAngles,
-                                       const SMESH::double_array & theAngles,
-                                       CORBA::Boolean              theHasRefPoint,
-                                       const SMESH::PointStruct &  theRefPoint)
-{
-  MESSAGE("ExtrusionAlongPath");
-  if ( !myIsPreviewMode ) {
-    TPythonDump() << "error = " << this << ".ExtrusionAlongPath( "
-                  << theIDsOfElements << ", "
-                  << thePathMesh      << ", "
-                  << thePathShape     << ", "
-                  << theNodeStart     << ", "
-                  << theHasAngles     << ", "
-                  << theAngles        << ", "
-                  << theHasRefPoint   << ", "
-                  << "SMESH.PointStruct( "
-                  << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
-                  << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
-                  << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ) )";
-  }
-  SMESH::SMESH_MeshEditor::Extrusion_Error anError;
-  extrusionAlongPath( theIDsOfElements,
-                      thePathMesh,
-                      thePathShape,
-                      theNodeStart,
-                      theHasAngles,
-                      theAngles,
-                      theHasRefPoint,
-                      theRefPoint,
-                      false,
-                      anError);
-  return anError;
-}
-
-//=======================================================================
-//function : ExtrusionAlongPathObject
+//function : Translate
 //purpose  :
 //=======================================================================
 //purpose  :
 //=======================================================================
-SMESH::SMESH_MeshEditor::Extrusion_Error
-SMESH_MeshEditor_i::ExtrusionAlongPathObject(SMESH::SMESH_IDSource_ptr   theObject,
-                                             SMESH::SMESH_Mesh_ptr       thePathMesh,
-                                             GEOM::GEOM_Object_ptr       thePathShape,
-                                             CORBA::Long                 theNodeStart,
-                                             CORBA::Boolean              theHasAngles,
-                                             const SMESH::double_array & theAngles,
-                                             CORBA::Boolean              theHasRefPoint,
-                                             const SMESH::PointStruct &  theRefPoint)
+
+void SMESH_MeshEditor_i::Translate(const SMESH::long_array & theIDsOfElements,
+                                   const SMESH::DirStruct &  theVector,
+                                   CORBA::Boolean            theCopy)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  if ( !myIsPreviewMode ) {
-    TPythonDump() << "error = " << this << ".ExtrusionAlongPathObject( "
-                  << theObject        << ", "
-                  << thePathMesh      << ", "
-                  << thePathShape     << ", "
-                  << theNodeStart     << ", "
-                  << theHasAngles     << ", "
-                  << theAngles        << ", "
-                  << theHasRefPoint   << ", "
-                  << "SMESH.PointStruct( "
-                  << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
-                  << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
-                  << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ) )";
-  }
-  SMESH::SMESH_MeshEditor::Extrusion_Error anError;
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  extrusionAlongPath( anElementsId,
-                      thePathMesh,
-                      thePathShape,
-                      theNodeStart,
-                      theHasAngles,
-                      theAngles,
-                      theHasRefPoint,
-                      theRefPoint,
-                      false,
-                      anError);
-  return anError;
+  if (!myIsPreviewMode) {
+    TPythonDump() << this << ".Translate( "
+                  << theIDsOfElements << ", "
+                  << theVector        << ", "
+                  << theCopy          << " )";
+  }
+  if (theIDsOfElements.length()) {
+    TIDSortedElemSet elements;
+    arrayToSet(theIDsOfElements, getMeshDS(), elements);
+    translate(elements, theVector, theCopy, false);
+  }
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : ExtrusionAlongPathObject1D
-//purpose  :
-//=======================================================================
-SMESH::SMESH_MeshEditor::Extrusion_Error
-SMESH_MeshEditor_i::ExtrusionAlongPathObject1D(SMESH::SMESH_IDSource_ptr   theObject,
-                                               SMESH::SMESH_Mesh_ptr       thePathMesh,
-                                               GEOM::GEOM_Object_ptr       thePathShape,
-                                               CORBA::Long                 theNodeStart,
-                                               CORBA::Boolean              theHasAngles,
-                                               const SMESH::double_array & theAngles,
-                                               CORBA::Boolean              theHasRefPoint,
-                                               const SMESH::PointStruct &  theRefPoint)
-{
-  if ( !myIsPreviewMode ) {
-    TPythonDump() << "error = " << this << ".ExtrusionAlongPathObject1D( "
-                  << theObject        << ", "
-                  << thePathMesh      << ", "
-                  << thePathShape     << ", "
-                  << theNodeStart     << ", "
-                  << theHasAngles     << ", "
-                  << theAngles        << ", "
-                  << theHasRefPoint   << ", "
-                  << "SMESH.PointStruct( "
-                  << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
-                  << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
-                  << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ) )";
-  }
-  SMESH::SMESH_MeshEditor::Extrusion_Error anError;
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  extrusionAlongPath( anElementsId,
-                      thePathMesh,
-                      thePathShape,
-                      theNodeStart,
-                      theHasAngles,
-                      theAngles,
-                      theHasRefPoint,
-                      theRefPoint,
-                      false,
-                      anError,
-                      SMDSAbs_Edge);
-  return anError;
-}
-
-//=======================================================================
-//function : ExtrusionAlongPathObject2D
+//function : TranslateObject
 //purpose  :
 //=======================================================================
 //purpose  :
 //=======================================================================
-SMESH::SMESH_MeshEditor::Extrusion_Error
-SMESH_MeshEditor_i::ExtrusionAlongPathObject2D(SMESH::SMESH_IDSource_ptr   theObject,
-                                               SMESH::SMESH_Mesh_ptr       thePathMesh,
-                                               GEOM::GEOM_Object_ptr       thePathShape,
-                                               CORBA::Long                 theNodeStart,
-                                               CORBA::Boolean              theHasAngles,
-                                               const SMESH::double_array & theAngles,
-                                               CORBA::Boolean              theHasRefPoint,
-                                               const SMESH::PointStruct &  theRefPoint)
+
+void SMESH_MeshEditor_i::TranslateObject(SMESH::SMESH_IDSource_ptr theObject,
+                                         const SMESH::DirStruct &  theVector,
+                                         CORBA::Boolean            theCopy)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  if ( !myIsPreviewMode ) {
-    TPythonDump() << "error = " << this << ".ExtrusionAlongPathObject2D( "
-                  << theObject        << ", "
-                  << thePathMesh      << ", "
-                  << thePathShape     << ", "
-                  << theNodeStart     << ", "
-                  << theHasAngles     << ", "
-                  << theAngles        << ", "
-                  << theHasRefPoint   << ", "
-                  << "SMESH.PointStruct( "
-                  << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
-                  << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
-                  << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ) )";
-  }
-  SMESH::SMESH_MeshEditor::Extrusion_Error anError;
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  extrusionAlongPath( anElementsId,
-                      thePathMesh,
-                      thePathShape,
-                      theNodeStart,
-                      theHasAngles,
-                      theAngles,
-                      theHasRefPoint,
-                      theRefPoint,
-                      false,
-                      anError,
-                      SMDSAbs_Face);
-  return anError;
-}
+  if (!myIsPreviewMode) {
+    TPythonDump() << this << ".TranslateObject( "
+                  << theObject << ", "
+                  << theVector << ", "
+                  << theCopy   << " )";
+  }
+  TIDSortedElemSet elements;
+
+  bool emptyIfIsMesh = myIsPreviewMode ? false : true;
 
 
+  if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
+    translate(elements, theVector, theCopy, false);
+}
 
 //=======================================================================
 
 //=======================================================================
-//function : ExtrusionAlongPathMakeGroups
+//function : TranslateMakeGroups
 //purpose  :
 //=======================================================================
 //purpose  :
 //=======================================================================
+
 SMESH::ListOfGroups*
 SMESH::ListOfGroups*
-SMESH_MeshEditor_i::ExtrusionAlongPathMakeGroups(const SMESH::long_array&   theIDsOfElements,
-                                                 SMESH::SMESH_Mesh_ptr      thePathMesh,
-                                                 GEOM::GEOM_Object_ptr      thePathShape,
-                                                 CORBA::Long                theNodeStart,
-                                                 CORBA::Boolean             theHasAngles,
-                                                 const SMESH::double_array& theAngles,
-                                                 CORBA::Boolean             theHasRefPoint,
-                                                 const SMESH::PointStruct&  theRefPoint,
-                                                 SMESH::SMESH_MeshEditor::Extrusion_Error& Error)
+SMESH_MeshEditor_i::TranslateMakeGroups(const SMESH::long_array& theIDsOfElements,
+                                        const SMESH::DirStruct&  theVector)
+  throw (SALOME::SALOME_Exception)
 {
   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
 
 {
   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
 
-  SMESH::ListOfGroups * aGroups =  extrusionAlongPath( theIDsOfElements,
-                                                       thePathMesh,
-                                                       thePathShape,
-                                                       theNodeStart,
-                                                       theHasAngles,
-                                                       theAngles,
-                                                       theHasRefPoint,
-                                                       theRefPoint,
-                                                       true,
-                                                       Error);
+  SMESH::ListOfGroups * aGroups = 0;
+  if (theIDsOfElements.length()) {
+    TIDSortedElemSet elements;
+    arrayToSet(theIDsOfElements, getMeshDS(), elements);
+    aGroups = translate(elements,theVector,true,true);
+  }
   if (!myIsPreviewMode) {
   if (!myIsPreviewMode) {
-    bool isDumpGroups = aGroups && aGroups->length() > 0;
-    if (isDumpGroups)
-      aPythonDump << "(" << aGroups << ", error)";
-    else
-      aPythonDump <<"error";
-
-    aPythonDump<<" = "<< this << ".ExtrusionAlongPathMakeGroups( "
-               << theIDsOfElements << ", "
-               << thePathMesh      << ", "
-               << thePathShape     << ", "
-               << theNodeStart     << ", "
-               << theHasAngles     << ", "
-               << theAngles        << ", "
-               << theHasRefPoint   << ", "
-               << "SMESH.PointStruct( "
-               << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
-               << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
-               << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ) )";
+    dumpGroupsList(aPythonDump, aGroups);
+    aPythonDump << this << ".TranslateMakeGroups( "
+                << theIDsOfElements << ", "
+                << theVector        << " )";
   }
   return aGroups;
 }
 
 //=======================================================================
   }
   return aGroups;
 }
 
 //=======================================================================
-//function : ExtrusionAlongPathObjectMakeGroups
+//function : TranslateObjectMakeGroups
 //purpose  :
 //=======================================================================
 //purpose  :
 //=======================================================================
-SMESH::ListOfGroups* SMESH_MeshEditor_i::
-ExtrusionAlongPathObjectMakeGroups(SMESH::SMESH_IDSource_ptr  theObject,
-                                   SMESH::SMESH_Mesh_ptr      thePathMesh,
-                                   GEOM::GEOM_Object_ptr      thePathShape,
-                                   CORBA::Long                theNodeStart,
-                                   CORBA::Boolean             theHasAngles,
-                                   const SMESH::double_array& theAngles,
-                                   CORBA::Boolean             theHasRefPoint,
-                                   const SMESH::PointStruct&  theRefPoint,
-                                   SMESH::SMESH_MeshEditor::Extrusion_Error& Error)
+
+SMESH::ListOfGroups*
+SMESH_MeshEditor_i::TranslateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
+                                              const SMESH::DirStruct&   theVector)
+  throw (SALOME::SALOME_Exception)
 {
   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
 
 {
   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
 
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  SMESH::ListOfGroups * aGroups = extrusionAlongPath( anElementsId,
-                                                      thePathMesh,
-                                                      thePathShape,
-                                                      theNodeStart,
-                                                      theHasAngles,
-                                                      theAngles,
-                                                      theHasRefPoint,
-                                                      theRefPoint,
-                                                      true,
-                                                      Error);
+  SMESH::ListOfGroups * aGroups = 0;
+  TIDSortedElemSet elements;
+  if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
+    aGroups = translate(elements, theVector, true, true);
 
   if (!myIsPreviewMode) {
 
   if (!myIsPreviewMode) {
-    bool isDumpGroups = aGroups && aGroups->length() > 0;
-    if (isDumpGroups)
-      aPythonDump << "(" << aGroups << ", error)";
-    else
-      aPythonDump <<"error";
-
-    aPythonDump << " = " << this << ".ExtrusionAlongPathObjectMakeGroups( "
+    dumpGroupsList(aPythonDump, aGroups);
+    aPythonDump << this << ".TranslateObjectMakeGroups( "
                 << theObject << ", "
                 << theObject << ", "
-                << thePathMesh      << ", "
-                << thePathShape     << ", "
-                << theNodeStart     << ", "
-                << theHasAngles     << ", "
-                << theAngles        << ", "
-                << theHasRefPoint   << ", "
-                << "SMESH.PointStruct( "
-                << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
-                << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
-                << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ) )";
+                << theVector << " )";
   }
   return aGroups;
 }
 
 //=======================================================================
   }
   return aGroups;
 }
 
 //=======================================================================
-//function : ExtrusionAlongPathObject1DMakeGroups
+//function : TranslateMakeMesh
 //purpose  :
 //=======================================================================
 //purpose  :
 //=======================================================================
-SMESH::ListOfGroups* SMESH_MeshEditor_i::
-ExtrusionAlongPathObject1DMakeGroups(SMESH::SMESH_IDSource_ptr  theObject,
-                                     SMESH::SMESH_Mesh_ptr      thePathMesh,
-                                     GEOM::GEOM_Object_ptr      thePathShape,
-                                     CORBA::Long                theNodeStart,
-                                     CORBA::Boolean             theHasAngles,
-                                     const SMESH::double_array& theAngles,
-                                     CORBA::Boolean             theHasRefPoint,
-                                     const SMESH::PointStruct&  theRefPoint,
-                                     SMESH::SMESH_MeshEditor::Extrusion_Error& Error)
-{
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
 
 
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  SMESH::ListOfGroups * aGroups = extrusionAlongPath( anElementsId,
-                                                      thePathMesh,
-                                                      thePathShape,
-                                                      theNodeStart,
-                                                      theHasAngles,
-                                                      theAngles,
-                                                      theHasRefPoint,
-                                                      theRefPoint,
-                                                      true,
-                                                      Error,
-                                                      SMDSAbs_Edge);
-
-  if (!myIsPreviewMode) {
-    bool isDumpGroups = aGroups && aGroups->length() > 0;
-    if (isDumpGroups)
-      aPythonDump << "(" << aGroups << ", error)";
-    else
-      aPythonDump << "error";
-
-    aPythonDump << " = " << this << ".ExtrusionAlongPathObject1DMakeGroups( "
-                << theObject << ", "
-                << thePathMesh      << ", "
-                << thePathShape     << ", "
-                << theNodeStart     << ", "
-                << theHasAngles     << ", "
-                << theAngles        << ", "
-                << theHasRefPoint   << ", "
-                << "SMESH.PointStruct( "
-                << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
-                << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
-                << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ) )";
-  }
-  return aGroups;
-}
-
-//=======================================================================
-//function : ExtrusionAlongPathObject2DMakeGroups
-//purpose  :
-//=======================================================================
-SMESH::ListOfGroups* SMESH_MeshEditor_i::
-ExtrusionAlongPathObject2DMakeGroups(SMESH::SMESH_IDSource_ptr  theObject,
-                                     SMESH::SMESH_Mesh_ptr      thePathMesh,
-                                     GEOM::GEOM_Object_ptr      thePathShape,
-                                     CORBA::Long                theNodeStart,
-                                     CORBA::Boolean             theHasAngles,
-                                     const SMESH::double_array& theAngles,
-                                     CORBA::Boolean             theHasRefPoint,
-                                     const SMESH::PointStruct&  theRefPoint,
-                                     SMESH::SMESH_MeshEditor::Extrusion_Error& Error)
+SMESH::SMESH_Mesh_ptr
+SMESH_MeshEditor_i::TranslateMakeMesh(const SMESH::long_array& theIDsOfElements,
+                                      const SMESH::DirStruct&  theVector,
+                                      CORBA::Boolean           theCopyGroups,
+                                      const char*              theMeshName)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+  SMESH_Mesh_i* mesh_i;
+  SMESH::SMESH_Mesh_var mesh;
 
 
-  SMESH::long_array_var anElementsId = theObject->GetIDs();
-  SMESH::ListOfGroups * aGroups = extrusionAlongPath( anElementsId,
-                                                      thePathMesh,
-                                                      thePathShape,
-                                                      theNodeStart,
-                                                      theHasAngles,
-                                                      theAngles,
-                                                      theHasRefPoint,
-                                                      theRefPoint,
-                                                      true,
-                                                      Error,
-                                                      SMDSAbs_Face);
+  { // open new scope to dump "MakeMesh" command
+    // and then "GetGroups" using SMESH_Mesh::GetGroups()
 
 
-  if (!myIsPreviewMode) {
-    bool isDumpGroups = aGroups && aGroups->length() > 0;
-    if (isDumpGroups)
-      aPythonDump << "(" << aGroups << ", error)";
-    else
-      aPythonDump << "error";
+    TPythonDump pydump; // to prevent dump at mesh creation
 
 
-    aPythonDump << " = " << this << ".ExtrusionAlongPathObject2DMakeGroups( "
-                << theObject << ", "
-                << thePathMesh      << ", "
-                << thePathShape     << ", "
-                << theNodeStart     << ", "
-                << theHasAngles     << ", "
-                << theAngles        << ", "
-                << theHasRefPoint   << ", "
-                << "SMESH.PointStruct( "
-                << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
-                << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
-                << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ) )";
-  }
-  return aGroups;
-}
+    mesh = makeMesh( theMeshName );
+    mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
 
 
+    if ( mesh_i && theIDsOfElements.length() )
+    {
+      TIDSortedElemSet elements;
+      arrayToSet(theIDsOfElements, getMeshDS(), elements);
+      translate(elements, theVector, false, theCopyGroups, & mesh_i->GetImpl());
+      mesh_i->CreateGroupServants();
+    }
 
 
-//=======================================================================
-//function : ExtrusionAlongPathObjX
-//purpose  :
-//=======================================================================
-SMESH::ListOfGroups* SMESH_MeshEditor_i::
-ExtrusionAlongPathObjX(SMESH::SMESH_IDSource_ptr  Object,
-                       SMESH::SMESH_IDSource_ptr  Path,
-                       CORBA::Long                NodeStart,
-                       CORBA::Boolean             HasAngles,
-                       const SMESH::double_array& Angles,
-                       CORBA::Boolean             LinearVariation,
-                       CORBA::Boolean             HasRefPoint,
-                       const SMESH::PointStruct&  RefPoint,
-                       CORBA::Boolean             MakeGroups,
-                       SMESH::ElementType         ElemType,
-                       SMESH::SMESH_MeshEditor::Extrusion_Error& Error)
-{
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+    if ( !myIsPreviewMode ) {
+      pydump << mesh << " = " << this << ".TranslateMakeMesh( "
+             << theIDsOfElements << ", "
+             << theVector        << ", "
+             << theCopyGroups    << ", '"
+             << theMeshName      << "' )";
+    }
+  }
 
 
-  SMESH::long_array_var anElementsId = Object->GetIDs();
-  SMESH::ListOfGroups * aGroups = extrusionAlongPathX(anElementsId,
-                                                      Path,
-                                                      NodeStart,
-                                                      HasAngles,
-                                                      Angles,
-                                                      LinearVariation,
-                                                      HasRefPoint,
-                                                      RefPoint,
-                                                      MakeGroups,
-                                                      (SMDSAbs_ElementType)ElemType,
-                                                      Error);
+  //dump "GetGroups"
+  if (!myIsPreviewMode && mesh_i)
+    mesh_i->GetGroups();
 
 
-  if (!myIsPreviewMode) {
-    bool isDumpGroups = aGroups && aGroups->length() > 0;
-    if (isDumpGroups)
-      aPythonDump << "(" << *aGroups << ", error)";
-    else
-      aPythonDump << "error";
-
-    aPythonDump << " = " << this << ".ExtrusionAlongPathObjX( "
-                << Object          << ", "
-                << Path            << ", "
-                << NodeStart       << ", "
-                << HasAngles       << ", "
-                << TVar( Angles )  << ", "
-                << LinearVariation << ", "
-                << HasRefPoint     << ", "
-                << "SMESH.PointStruct( "
-                << TVar( HasRefPoint ? RefPoint.x : 0 ) << ", "
-                << TVar( HasRefPoint ? RefPoint.y : 0 ) << ", "
-                << TVar( HasRefPoint ? RefPoint.z : 0 ) << " ), "
-                << MakeGroups << ", "
-                << ElemType << " )";
-  }
-  return aGroups;
+  return mesh._retn();
 }
 
 }
 
-
 //=======================================================================
 //=======================================================================
-//function : ExtrusionAlongPathX
+//function : TranslateObjectMakeMesh
 //purpose  :
 //=======================================================================
 //purpose  :
 //=======================================================================
-SMESH::ListOfGroups* SMESH_MeshEditor_i::
-ExtrusionAlongPathX(const SMESH::long_array&   IDsOfElements,
-                    SMESH::SMESH_IDSource_ptr  Path,
-                    CORBA::Long                NodeStart,
-                    CORBA::Boolean             HasAngles,
-                    const SMESH::double_array& Angles,
-                    CORBA::Boolean             LinearVariation,
-                    CORBA::Boolean             HasRefPoint,
-                    const SMESH::PointStruct&  RefPoint,
-                    CORBA::Boolean             MakeGroups,
-                    SMESH::ElementType         ElemType,
-                    SMESH::SMESH_MeshEditor::Extrusion_Error& Error)
-{
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
-
-  SMESH::ListOfGroups * aGroups = extrusionAlongPathX(IDsOfElements,
-                                                      Path,
-                                                      NodeStart,
-                                                      HasAngles,
-                                                      Angles,
-                                                      LinearVariation,
-                                                      HasRefPoint,
-                                                      RefPoint,
-                                                      MakeGroups,
-                                                      (SMDSAbs_ElementType)ElemType,
-                                                      Error);
-
-  if (!myIsPreviewMode) {
-    bool isDumpGroups = aGroups && aGroups->length() > 0;
-    if (isDumpGroups)
-      aPythonDump << "(" << *aGroups << ", error)";
-    else
-      aPythonDump <<"error";
-
-    aPythonDump << " = " << this << ".ExtrusionAlongPathX( "
-                << IDsOfElements   << ", "
-                << Path            << ", "
-                << NodeStart       << ", "
-                << HasAngles       << ", "
-                << TVar( Angles )  << ", "
-                << LinearVariation << ", "
-                << HasRefPoint     << ", "
-                << "SMESH.PointStruct( "
-                << TVar( HasRefPoint ? RefPoint.x : 0 ) << ", "
-                << TVar( HasRefPoint ? RefPoint.y : 0 ) << ", "
-                << TVar( HasRefPoint ? RefPoint.z : 0 ) << " ), "
-                << MakeGroups << ", "
-                << ElemType << " )";
-  }
-  return aGroups;
-}
 
 
+SMESH::SMESH_Mesh_ptr
+SMESH_MeshEditor_i::TranslateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
+                                            const SMESH::DirStruct&   theVector,
+                                            CORBA::Boolean            theCopyGroups,
+                                            const char*               theMeshName)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH_TRY;
+  SMESH_Mesh_i* mesh_i;
+  SMESH::SMESH_Mesh_var mesh;
+  { // open new scope to dump "MakeMesh" command
+    // and then "GetGroups" using SMESH_Mesh::GetGroups()
 
 
-//================================================================================
-/*!
- * \brief Compute rotation angles for ExtrusionAlongPath as linear variation
- * of given angles along path steps
- * \param PathMesh mesh containing a 1D sub-mesh on the edge, along
- *                which proceeds the extrusion
- * \param PathShape is shape(edge); as the mesh can be complex, the edge
- *                 is used to define the sub-mesh for the path
- */
-//================================================================================
+    TPythonDump pydump; // to prevent dump at mesh creation
+    mesh = makeMesh( theMeshName );
+    mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
 
 
-SMESH::double_array*
-SMESH_MeshEditor_i::LinearAnglesVariation(SMESH::SMESH_Mesh_ptr       thePathMesh,
-                                          GEOM::GEOM_Object_ptr       thePathShape,
-                                          const SMESH::double_array & theAngles)
-{
-  SMESH::double_array_var aResult = new SMESH::double_array();
-  int nbAngles = theAngles.length();
-  if ( nbAngles > 0 && !thePathMesh->_is_nil() && !thePathShape->_is_nil() )
-  {
-    SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
-    TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
-    SMESH_subMesh* aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
-    if ( !aSubMesh || !aSubMesh->GetSubMeshDS())
-      return aResult._retn();
-    int nbSteps = aSubMesh->GetSubMeshDS()->NbElements();
-    if ( nbSteps == nbAngles )
+    TIDSortedElemSet elements;
+    if ( mesh_i &&
+         idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
     {
     {
-      aResult.inout() = theAngles;
+      translate(elements, theVector,false, theCopyGroups, & mesh_i->GetImpl());
+      mesh_i->CreateGroupServants();
     }
     }
-    else
-    {
-      aResult->length( nbSteps );
-      double rAn2St = double( nbAngles ) / double( nbSteps );
-      double angPrev = 0, angle;
-      for ( int iSt = 0; iSt < nbSteps; ++iSt )
-      {
-        double angCur = rAn2St * ( iSt+1 );
-        double angCurFloor  = floor( angCur );
-        double angPrevFloor = floor( angPrev );
-        if ( angPrevFloor == 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 ];
-        }
-        aResult[ iSt ] = angle;
-        angPrev = angCur;
-      }
+    if ( !myIsPreviewMode ) {
+      pydump << mesh << " = " << this << ".TranslateObjectMakeMesh( "
+             << theObject     << ", "
+             << theVector     << ", "
+             << theCopyGroups << ", '"
+             << theMeshName   << "' )";
     }
   }
     }
   }
-  // Update Python script
-  TPythonDump() << "rotAngles = " << theAngles;
-  TPythonDump() << "rotAngles = " << this << ".LinearAnglesVariation( "
-                << thePathMesh  << ", "
-                << thePathShape << ", "
-                << "rotAngles )";
 
 
-  return aResult._retn();
-}
+  // dump "GetGroups"
+  if (!myIsPreviewMode && mesh_i)
+    mesh_i->GetGroups();
+
+  return mesh._retn();
 
 
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
 
 //=======================================================================
 
 //=======================================================================
-//function : mirror
+//function : rotate
 //purpose  :
 //=======================================================================
 
 SMESH::ListOfGroups*
 //purpose  :
 //=======================================================================
 
 SMESH::ListOfGroups*
-SMESH_MeshEditor_i::mirror(TIDSortedElemSet &                  theElements,
-                           const SMESH::AxisStruct &           theAxis,
-                           SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
-                           CORBA::Boolean                      theCopy,
-                           bool                                theMakeGroups,
-                           ::SMESH_Mesh*                       theTargetMesh)
+SMESH_MeshEditor_i::rotate(TIDSortedElemSet &        theElements,
+                           const SMESH::AxisStruct & theAxis,
+                           CORBA::Double             theAngle,
+                           CORBA::Boolean            theCopy,
+                           bool                      theMakeGroups,
+                           ::SMESH_Mesh*             theTargetMesh)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   initData();
 
-  gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
-  gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
-
   if ( theTargetMesh )
     theCopy = false;
 
   if ( theTargetMesh )
     theCopy = false;
 
+  gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
+  gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
+
   gp_Trsf aTrsf;
   gp_Trsf aTrsf;
-  switch ( theMirrorType ) {
-  case  SMESH::SMESH_MeshEditor::POINT:
-    aTrsf.SetMirror( P );
-    break;
-  case  SMESH::SMESH_MeshEditor::AXIS:
-    aTrsf.SetMirror( gp_Ax1( P, V ));
-    break;
-  default:
-    aTrsf.SetMirror( gp_Ax2( P, V ));
-  }
+  aTrsf.SetRotation( gp_Ax1( P, V ), theAngle);
 
   TIDSortedElemSet  copyElements;
 
   TIDSortedElemSet  copyElements;
-  TIDSortedElemSet* workElements = & theElements;
-
-  if ( myIsPreviewMode )
-  {
+  TIDSortedElemSet* workElements = &theElements;
+  if ( myIsPreviewMode ) {
     TPreviewMesh * tmpMesh = getPreviewMesh();
     TPreviewMesh * tmpMesh = getPreviewMesh();
-    tmpMesh->Copy( theElements, copyElements);
+    tmpMesh->Copy( theElements, copyElements );
     if ( !theCopy && !theTargetMesh )
     {
       TIDSortedElemSet elemsAround, elemsAroundCopy;
       getElementsAround( theElements, getMeshDS(), elemsAround );
       tmpMesh->Copy( elemsAround, elemsAroundCopy);
     }
     if ( !theCopy && !theTargetMesh )
     {
       TIDSortedElemSet elemsAround, elemsAroundCopy;
       getElementsAround( theElements, getMeshDS(), elemsAround );
       tmpMesh->Copy( elemsAround, elemsAroundCopy);
     }
-    workElements = & copyElements;
+    workElements = &copyElements;
     theMakeGroups = false;
   }
 
   ::SMESH_MeshEditor::PGroupIDs groupIds =
       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
 
     theMakeGroups = false;
   }
 
   ::SMESH_MeshEditor::PGroupIDs groupIds =
       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
 
-  if ( theCopy && !myIsPreviewMode)
+  if ( !myIsPreviewMode)
   {
   {
-    if ( theTargetMesh )
-    {
-      theTargetMesh->GetMeshDS()->Modified();
-    }
-    else
-    {
-      myMesh->GetMeshDS()->Modified();
-      myMesh->SetIsModified( true );
-    }
+    if ( theTargetMesh ) theTargetMesh->GetMeshDS()->Modified();
+    else                 declareMeshModified( /*isReComputeSafe=*/false );
   }
   }
+
   return theMakeGroups ? getGroups(groupIds.get()) : 0;
   return theMakeGroups ? getGroups(groupIds.get()) : 0;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : Mirror
+//function : Rotate
 //purpose  :
 //=======================================================================
 
 //purpose  :
 //=======================================================================
 
-void SMESH_MeshEditor_i::Mirror(const SMESH::long_array &           theIDsOfElements,
-                                const SMESH::AxisStruct &           theAxis,
-                                SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
-                                CORBA::Boolean                      theCopy)
+void SMESH_MeshEditor_i::Rotate(const SMESH::long_array & theIDsOfElements,
+                                const SMESH::AxisStruct & theAxis,
+                                CORBA::Double             theAngle,
+                                CORBA::Boolean            theCopy)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  if ( !myIsPreviewMode ) {
-    TPythonDump() << this << ".Mirror( "
-                  << theIDsOfElements              << ", "
-                  << theAxis                       << ", "
-                  << mirrorTypeName(theMirrorType) << ", "
-                  << theCopy                       << " )";
+  if (!myIsPreviewMode) {
+    TPythonDump() << this << ".Rotate( "
+                  << theIDsOfElements << ", "
+                  << theAxis          << ", "
+                  << TVar( theAngle ) << ", "
+                  << theCopy          << " )";
   }
   }
-  if ( theIDsOfElements.length() > 0 )
+  if (theIDsOfElements.length() > 0)
   {
     TIDSortedElemSet elements;
     arrayToSet(theIDsOfElements, getMeshDS(), elements);
   {
     TIDSortedElemSet elements;
     arrayToSet(theIDsOfElements, getMeshDS(), elements);
-    mirror(elements, theAxis, theMirrorType, theCopy, false);
+    rotate(elements,theAxis,theAngle,theCopy,false);
   }
 }
 
   }
 }
 
-
 //=======================================================================
 //=======================================================================
-//function : MirrorObject
+//function : RotateObject
 //purpose  :
 //=======================================================================
 
 //purpose  :
 //=======================================================================
 
-void SMESH_MeshEditor_i::MirrorObject(SMESH::SMESH_IDSource_ptr           theObject,
-                                      const SMESH::AxisStruct &           theAxis,
-                                      SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
-                                      CORBA::Boolean                      theCopy)
+void SMESH_MeshEditor_i::RotateObject(SMESH::SMESH_IDSource_ptr theObject,
+                                      const SMESH::AxisStruct & theAxis,
+                                      CORBA::Double             theAngle,
+                                      CORBA::Boolean            theCopy)
+  throw (SALOME::SALOME_Exception)
 {
   if ( !myIsPreviewMode ) {
 {
   if ( !myIsPreviewMode ) {
-    TPythonDump() << this << ".MirrorObject( "
-                  << theObject                     << ", "
-                  << theAxis                       << ", "
-                  << mirrorTypeName(theMirrorType) << ", "
-                  << theCopy                       << " )";
+    TPythonDump() << this << ".RotateObject( "
+                  << theObject        << ", "
+                  << theAxis          << ", "
+                  << TVar( theAngle ) << ", "
+                  << theCopy          << " )";
   }
   TIDSortedElemSet elements;
   }
   TIDSortedElemSet elements;
-
   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
-
   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
-    mirror(elements, theAxis, theMirrorType, theCopy, false);
+    rotate(elements,theAxis,theAngle,theCopy,false);
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : MirrorMakeGroups
+//function : RotateMakeGroups
 //purpose  :
 //=======================================================================
 
 SMESH::ListOfGroups*
 //purpose  :
 //=======================================================================
 
 SMESH::ListOfGroups*
-SMESH_MeshEditor_i::MirrorMakeGroups(const SMESH::long_array&            theIDsOfElements,
-                                     const SMESH::AxisStruct&            theMirror,
-                                     SMESH::SMESH_MeshEditor::MirrorType theMirrorType)
+SMESH_MeshEditor_i::RotateMakeGroups(const SMESH::long_array& theIDsOfElements,
+                                     const SMESH::AxisStruct& theAxis,
+                                     CORBA::Double            theAngle)
+  throw (SALOME::SALOME_Exception)
 {
   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
 
   SMESH::ListOfGroups * aGroups = 0;
 {
   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
 
   SMESH::ListOfGroups * aGroups = 0;
-  if ( theIDsOfElements.length() > 0 )
+  if (theIDsOfElements.length() > 0)
   {
     TIDSortedElemSet elements;
     arrayToSet(theIDsOfElements, getMeshDS(), elements);
   {
     TIDSortedElemSet elements;
     arrayToSet(theIDsOfElements, getMeshDS(), elements);
-    aGroups = mirror(elements, theMirror, theMirrorType, true, true);
+    aGroups = rotate(elements,theAxis,theAngle,true,true);
   }
   if (!myIsPreviewMode) {
   }
   if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".MirrorMakeGroups( "
-                << theIDsOfElements              << ", "
-                << theMirror                     << ", "
-                << mirrorTypeName(theMirrorType) << " )";
+    dumpGroupsList(aPythonDump, aGroups);
+    aPythonDump << this << ".RotateMakeGroups( "
+                << theIDsOfElements << ", "
+                << theAxis          << ", "
+                << TVar( theAngle ) << " )";
   }
   return aGroups;
 }
 
 //=======================================================================
   }
   return aGroups;
 }
 
 //=======================================================================
-//function : MirrorObjectMakeGroups
+//function : RotateObjectMakeGroups
 //purpose  :
 //=======================================================================
 
 SMESH::ListOfGroups*
 //purpose  :
 //=======================================================================
 
 SMESH::ListOfGroups*
-SMESH_MeshEditor_i::MirrorObjectMakeGroups(SMESH::SMESH_IDSource_ptr           theObject,
-                                           const SMESH::AxisStruct&            theMirror,
-                                           SMESH::SMESH_MeshEditor::MirrorType theMirrorType)
+SMESH_MeshEditor_i::RotateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
+                                           const SMESH::AxisStruct&  theAxis,
+                                           CORBA::Double             theAngle)
+  throw (SALOME::SALOME_Exception)
 {
   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
 
   SMESH::ListOfGroups * aGroups = 0;
   TIDSortedElemSet elements;
 {
   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
 
   SMESH::ListOfGroups * aGroups = 0;
   TIDSortedElemSet elements;
-  if ( idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
-    aGroups = mirror(elements, theMirror, theMirrorType, true, true);
+  if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
+    aGroups = rotate(elements, theAxis, theAngle, true, true);
 
 
-  if (!myIsPreviewMode)
-  {
-    DumpGroupsList(aPythonDump,aGroups);
-    aPythonDump << this << ".MirrorObjectMakeGroups( "
-                << theObject                     << ", "
-                << theMirror                     << ", "
-                << mirrorTypeName(theMirrorType) << " )";
+  if (!myIsPreviewMode) {
+    dumpGroupsList(aPythonDump, aGroups);
+    aPythonDump << this << ".RotateObjectMakeGroups( "
+                << theObject        << ", "
+                << theAxis          << ", "
+                << TVar( theAngle ) << " )";
   }
   return aGroups;
 }
 
 //=======================================================================
   }
   return aGroups;
 }
 
 //=======================================================================
-//function : MirrorMakeMesh
+//function : RotateMakeMesh
 //purpose  :
 //=======================================================================
 
 SMESH::SMESH_Mesh_ptr
 //purpose  :
 //=======================================================================
 
 SMESH::SMESH_Mesh_ptr
-SMESH_MeshEditor_i::MirrorMakeMesh(const SMESH::long_array&            theIDsOfElements,
-                                   const SMESH::AxisStruct&            theMirror,
-                                   SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
-                                   CORBA::Boolean                      theCopyGroups,
-                                   const char*                         theMeshName)
+SMESH_MeshEditor_i::RotateMakeMesh(const SMESH::long_array& theIDsOfElements,
+                                   const SMESH::AxisStruct& theAxis,
+                                   CORBA::Double            theAngleInRadians,
+                                   CORBA::Boolean           theCopyGroups,
+                                   const char*              theMeshName)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  SMESH_Mesh_i* mesh_i;
+  SMESH_TRY;
   SMESH::SMESH_Mesh_var mesh;
   SMESH::SMESH_Mesh_var mesh;
+  SMESH_Mesh_i* mesh_i;
+
   { // open new scope to dump "MakeMesh" command
     // and then "GetGroups" using SMESH_Mesh::GetGroups()
 
   { // open new scope to dump "MakeMesh" command
     // and then "GetGroups" using SMESH_Mesh::GetGroups()
 
@@ -3641,110 +3801,145 @@ SMESH_MeshEditor_i::MirrorMakeMesh(const SMESH::long_array&            theIDsOfE
 
     mesh = makeMesh( theMeshName );
     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
 
     mesh = makeMesh( theMeshName );
     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
-    if (mesh_i && theIDsOfElements.length() > 0 )
+
+    if ( mesh_i && theIDsOfElements.length() > 0 )
     {
       TIDSortedElemSet elements;
       arrayToSet(theIDsOfElements, getMeshDS(), elements);
     {
       TIDSortedElemSet elements;
       arrayToSet(theIDsOfElements, getMeshDS(), elements);
-      mirror(elements, theMirror, theMirrorType,
+      rotate(elements, theAxis, theAngleInRadians,
              false, theCopyGroups, & mesh_i->GetImpl());
       mesh_i->CreateGroupServants();
     }
              false, theCopyGroups, & mesh_i->GetImpl());
       mesh_i->CreateGroupServants();
     }
-
-    if (!myIsPreviewMode) {
-      pydump << mesh << " = " << this << ".MirrorMakeMesh( "
-             << theIDsOfElements              << ", "
-             << theMirror                     << ", "
-             << mirrorTypeName(theMirrorType) << ", "
-             << theCopyGroups                 << ", '"
-             << theMeshName                   << "' )";
+    if ( !myIsPreviewMode ) {
+      pydump << mesh << " = " << this << ".RotateMakeMesh( "
+             << theIDsOfElements          << ", "
+             << theAxis                   << ", "
+             << TVar( theAngleInRadians ) << ", "
+             << theCopyGroups             << ", '"
+             << theMeshName               << "' )";
     }
   }
 
     }
   }
 
-  //dump "GetGroups"
-  if (!myIsPreviewMode && mesh_i)
+  // dump "GetGroups"
+  if (!myIsPreviewMode && mesh_i && theIDsOfElements.length() > 0 )
     mesh_i->GetGroups();
 
   return mesh._retn();
     mesh_i->GetGroups();
 
   return mesh._retn();
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : MirrorObjectMakeMesh
+//function : RotateObjectMakeMesh
 //purpose  :
 //=======================================================================
 
 SMESH::SMESH_Mesh_ptr
 //purpose  :
 //=======================================================================
 
 SMESH::SMESH_Mesh_ptr
-SMESH_MeshEditor_i::MirrorObjectMakeMesh(SMESH::SMESH_IDSource_ptr           theObject,
-                                         const SMESH::AxisStruct&            theMirror,
-                                         SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
-                                         CORBA::Boolean                      theCopyGroups,
-                                         const char*                         theMeshName)
+SMESH_MeshEditor_i::RotateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
+                                         const SMESH::AxisStruct&  theAxis,
+                                         CORBA::Double             theAngleInRadians,
+                                         CORBA::Boolean            theCopyGroups,
+                                         const char*               theMeshName)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  SMESH_Mesh_i* mesh_i;
+  SMESH_TRY;
   SMESH::SMESH_Mesh_var mesh;
   SMESH::SMESH_Mesh_var mesh;
-  { // open new scope to dump "MakeMesh" command
-    // and then "GetGroups" using SMESH_Mesh::GetGroups()
+  SMESH_Mesh_i* mesh_i;
 
 
-    TPythonDump pydump; // to prevent dump at mesh creation
+  {// open new scope to dump "MakeMesh" command
+   // and then "GetGroups" using SMESH_Mesh::GetGroups()
 
 
+    TPythonDump pydump; // to prevent dump at mesh creation
     mesh = makeMesh( theMeshName );
     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
     mesh = makeMesh( theMeshName );
     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
+
     TIDSortedElemSet elements;
     TIDSortedElemSet elements;
-    if ( mesh_i &&
-         idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
+    if (mesh_i &&
+        idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
     {
     {
-      mirror(elements, theMirror, theMirrorType,
+      rotate(elements, theAxis, theAngleInRadians,
              false, theCopyGroups, & mesh_i->GetImpl());
       mesh_i->CreateGroupServants();
     }
              false, theCopyGroups, & mesh_i->GetImpl());
       mesh_i->CreateGroupServants();
     }
-    if (!myIsPreviewMode) {
-      pydump << mesh << " = " << this << ".MirrorObjectMakeMesh( "
-             << theObject                     << ", "
-             << theMirror                     << ", "
-             << mirrorTypeName(theMirrorType) << ", "
-             << theCopyGroups                 << ", '"
-             << theMeshName                   << "' )";
+    if ( !myIsPreviewMode ) {
+      pydump << mesh << " = " << this << ".RotateObjectMakeMesh( "
+             << theObject                 << ", "
+             << theAxis                   << ", "
+             << TVar( theAngleInRadians ) << ", "
+             << theCopyGroups             << ", '"
+             << theMeshName               << "' )";
     }
   }
 
     }
   }
 
-  //dump "GetGroups"
+  // dump "GetGroups"
   if (!myIsPreviewMode && mesh_i)
     mesh_i->GetGroups();
 
   return mesh._retn();
   if (!myIsPreviewMode && mesh_i)
     mesh_i->GetGroups();
 
   return mesh._retn();
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : translate
+//function : scale
 //purpose  :
 //=======================================================================
 
 SMESH::ListOfGroups*
 //purpose  :
 //=======================================================================
 
 SMESH::ListOfGroups*
-SMESH_MeshEditor_i::translate(TIDSortedElemSet        & theElements,
-                              const SMESH::DirStruct &  theVector,
-                              CORBA::Boolean            theCopy,
-                              bool                      theMakeGroups,
-                              ::SMESH_Mesh*             theTargetMesh)
+SMESH_MeshEditor_i::scale(SMESH::SMESH_IDSource_ptr  theObject,
+                          const SMESH::PointStruct&  thePoint,
+                          const SMESH::double_array& theScaleFact,
+                          CORBA::Boolean             theCopy,
+                          bool                       theMakeGroups,
+                          ::SMESH_Mesh*              theTargetMesh)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
   initData();
+  if ( theScaleFact.length() < 1 )
+    THROW_SALOME_CORBA_EXCEPTION("Scale factor not given", SALOME::BAD_PARAM);
+  if ( theScaleFact.length() == 2 )
+    THROW_SALOME_CORBA_EXCEPTION("Invalid nb of scale factors : 2", SALOME::BAD_PARAM);
 
   if ( theTargetMesh )
     theCopy = false;
 
 
   if ( theTargetMesh )
     theCopy = false;
 
+  TIDSortedElemSet elements;
+  bool emptyIfIsMesh = myIsPreviewMode ? false : true;
+  if ( !idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
+    return 0;
+
+  double S[3] = {
+    theScaleFact[0],
+    (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[1],
+    (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[2],
+  };
   gp_Trsf aTrsf;
   gp_Trsf aTrsf;
-  const SMESH::PointStruct * P = &theVector.PS;
-  aTrsf.SetTranslation( gp_Vec( P->x, P->y, P->z ));
 
 
-  TIDSortedElemSet  copyElements;
-  TIDSortedElemSet* workElements = &theElements;
+  // fight against orthogonalization
+  // aTrsf.SetValues( S[0], 0,    0,    thePoint.x * (1-S[0]),
+  //                  0,    S[1], 0,    thePoint.y * (1-S[1]),
+  //                  0,    0,    S[2], thePoint.z * (1-S[2]) );
+  aTrsf.SetScale( gp::Origin(), 1.0 ); // set form which is used to make group names
+  gp_XYZ & loc = ( gp_XYZ& ) aTrsf.TranslationPart();
+  gp_Mat & M   = ( gp_Mat& ) aTrsf.HVectorialPart();
+  loc.SetCoord( thePoint.x * (1-S[0]),
+                thePoint.y * (1-S[1]),
+                thePoint.z * (1-S[2]));
+  M.SetDiagonal( S[0], S[1], S[2] );
 
 
+  TIDSortedElemSet  copyElements;
+  TIDSortedElemSet* workElements = &elements;
   if ( myIsPreviewMode )
   {
     TPreviewMesh * tmpMesh = getPreviewMesh();
   if ( myIsPreviewMode )
   {
     TPreviewMesh * tmpMesh = getPreviewMesh();
-    tmpMesh->Copy( theElements, copyElements);
+    tmpMesh->Copy( elements, copyElements);
     if ( !theCopy && !theTargetMesh )
     {
       TIDSortedElemSet elemsAround, elemsAroundCopy;
     if ( !theCopy && !theTargetMesh )
     {
       TIDSortedElemSet elemsAround, elemsAroundCopy;
-      getElementsAround( theElements, getMeshDS(), elemsAround );
+      getElementsAround( elements, getMeshDS(), elemsAround );
       tmpMesh->Copy( elemsAround, elemsAroundCopy);
     }
     workElements = & copyElements;
       tmpMesh->Copy( elemsAround, elemsAroundCopy);
     }
     workElements = & copyElements;
@@ -3754,174 +3949,76 @@ SMESH_MeshEditor_i::translate(TIDSortedElemSet        & theElements,
   ::SMESH_MeshEditor::PGroupIDs groupIds =
       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
 
   ::SMESH_MeshEditor::PGroupIDs groupIds =
       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
 
-  if ( theCopy && !myIsPreviewMode )
+  if ( !myIsPreviewMode )
   {
   {
-    if ( theTargetMesh )
-    {
-      theTargetMesh->GetMeshDS()->Modified();
-    }
-    else
-    {
-      myMesh->GetMeshDS()->Modified();
-      myMesh->SetIsModified( true );
-    }
+    if ( theTargetMesh ) theTargetMesh->GetMeshDS()->Modified();
+    else                 declareMeshModified( /*isReComputeSafe=*/false );
   }
   }
-
   return theMakeGroups ? getGroups(groupIds.get()) : 0;
   return theMakeGroups ? getGroups(groupIds.get()) : 0;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : Translate
+//function : Scale
 //purpose  :
 //=======================================================================
 
 //purpose  :
 //=======================================================================
 
-void SMESH_MeshEditor_i::Translate(const SMESH::long_array & theIDsOfElements,
-                                   const SMESH::DirStruct &  theVector,
-                                   CORBA::Boolean            theCopy)
+void SMESH_MeshEditor_i::Scale(SMESH::SMESH_IDSource_ptr  theObject,
+                               const SMESH::PointStruct&  thePoint,
+                               const SMESH::double_array& theScaleFact,
+                               CORBA::Boolean             theCopy)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  if (!myIsPreviewMode) {
-    TPythonDump() << this << ".Translate( "
-                  << theIDsOfElements << ", "
-                  << theVector        << ", "
-                  << theCopy          << " )";
-  }
-  if (theIDsOfElements.length()) {
-    TIDSortedElemSet elements;
-    arrayToSet(theIDsOfElements, getMeshDS(), elements);
-    translate(elements, theVector, theCopy, false);
+  if ( !myIsPreviewMode ) {
+    TPythonDump() << this << ".Scale( "
+                  << theObject            << ", "
+                  << thePoint             << ", "
+                  << TVar( theScaleFact ) << ", "
+                  << theCopy              << " )";
   }
   }
+  scale(theObject, thePoint, theScaleFact, theCopy, false);
 }
 
 }
 
+
 //=======================================================================
 //=======================================================================
-//function : TranslateObject
+//function : ScaleMakeGroups
 //purpose  :
 //=======================================================================
 
 //purpose  :
 //=======================================================================
 
-void SMESH_MeshEditor_i::TranslateObject(SMESH::SMESH_IDSource_ptr theObject,
-                                         const SMESH::DirStruct &  theVector,
-                                         CORBA::Boolean            theCopy)
+SMESH::ListOfGroups*
+SMESH_MeshEditor_i::ScaleMakeGroups(SMESH::SMESH_IDSource_ptr  theObject,
+                                    const SMESH::PointStruct&  thePoint,
+                                    const SMESH::double_array& theScaleFact)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+
+  SMESH::ListOfGroups * aGroups = scale(theObject, thePoint, theScaleFact, true, true);
   if (!myIsPreviewMode) {
   if (!myIsPreviewMode) {
-    TPythonDump() << this << ".TranslateObject( "
-                  << theObject << ", "
-                  << theVector << ", "
-                  << theCopy   << " )";
-  }
-  TIDSortedElemSet elements;
-
-  bool emptyIfIsMesh = myIsPreviewMode ? false : true;
-  
-  if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
-    translate(elements, theVector, theCopy, false);
-}
-
-//=======================================================================
-//function : TranslateMakeGroups
-//purpose  :
-//=======================================================================
-
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::TranslateMakeGroups(const SMESH::long_array& theIDsOfElements,
-                                        const SMESH::DirStruct&  theVector)
-{
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
-
-  SMESH::ListOfGroups * aGroups = 0;
-  if (theIDsOfElements.length()) {
-    TIDSortedElemSet elements;
-    arrayToSet(theIDsOfElements, getMeshDS(), elements);
-    aGroups = translate(elements,theVector,true,true);
-  }
-  if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".TranslateMakeGroups( "
-                << theIDsOfElements << ", "
-                << theVector        << " )";
-  }
-  return aGroups;
-}
-
-//=======================================================================
-//function : TranslateObjectMakeGroups
-//purpose  :
-//=======================================================================
-
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::TranslateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
-                                              const SMESH::DirStruct&   theVector)
-{
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
-
-  SMESH::ListOfGroups * aGroups = 0;
-  TIDSortedElemSet elements;
-  if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
-    aGroups = translate(elements, theVector, true, true);
-
-  if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".TranslateObjectMakeGroups( "
-                << theObject << ", "
-                << theVector << " )";
+    dumpGroupsList(aPythonDump, aGroups);
+    aPythonDump << this << ".Scale("
+                << theObject            << ","
+                << thePoint             << ","
+                << TVar( theScaleFact ) << ",True,True)";
   }
   return aGroups;
 }
 
   }
   return aGroups;
 }
 
-//=======================================================================
-//function : TranslateMakeMesh
-//purpose  :
-//=======================================================================
-
-SMESH::SMESH_Mesh_ptr
-SMESH_MeshEditor_i::TranslateMakeMesh(const SMESH::long_array& theIDsOfElements,
-                                      const SMESH::DirStruct&  theVector,
-                                      CORBA::Boolean           theCopyGroups,
-                                      const char*              theMeshName)
-{
-  SMESH_Mesh_i* mesh_i;
-  SMESH::SMESH_Mesh_var mesh;
-
-  { // open new scope to dump "MakeMesh" command
-    // and then "GetGroups" using SMESH_Mesh::GetGroups()
-
-    TPythonDump pydump; // to prevent dump at mesh creation
-
-    mesh = makeMesh( theMeshName );
-    mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
-
-    if ( mesh_i && theIDsOfElements.length() )
-    {
-      TIDSortedElemSet elements;
-      arrayToSet(theIDsOfElements, getMeshDS(), elements);
-      translate(elements, theVector, false, theCopyGroups, & mesh_i->GetImpl());
-      mesh_i->CreateGroupServants();
-    }
-
-    if ( !myIsPreviewMode ) {
-      pydump << mesh << " = " << this << ".TranslateMakeMesh( "
-             << theIDsOfElements << ", "
-             << theVector        << ", "
-             << theCopyGroups    << ", '"
-             << theMeshName      << "' )";
-    }
-  }
-
-  //dump "GetGroups"
-  if (!myIsPreviewMode && mesh_i)
-    mesh_i->GetGroups();
-
-  return mesh._retn();
-}
 
 //=======================================================================
 
 //=======================================================================
-//function : TranslateObjectMakeMesh
+//function : ScaleMakeMesh
 //purpose  :
 //=======================================================================
 
 SMESH::SMESH_Mesh_ptr
 //purpose  :
 //=======================================================================
 
 SMESH::SMESH_Mesh_ptr
-SMESH_MeshEditor_i::TranslateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
-                                            const SMESH::DirStruct&   theVector,
-                                            CORBA::Boolean            theCopyGroups,
-                                            const char*               theMeshName)
+SMESH_MeshEditor_i::ScaleMakeMesh(SMESH::SMESH_IDSource_ptr  theObject,
+                                  const SMESH::PointStruct&  thePoint,
+                                  const SMESH::double_array& theScaleFact,
+                                  CORBA::Boolean             theCopyGroups,
+                                  const char*                theMeshName)
+  throw (SALOME::SALOME_Exception)
 {
   SMESH_Mesh_i* mesh_i;
   SMESH::SMESH_Mesh_var mesh;
 {
   SMESH_Mesh_i* mesh_i;
   SMESH::SMESH_Mesh_var mesh;
@@ -3929,23 +4026,21 @@ SMESH_MeshEditor_i::TranslateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
     // and then "GetGroups" using SMESH_Mesh::GetGroups()
 
     TPythonDump pydump; // to prevent dump at mesh creation
     // and then "GetGroups" using SMESH_Mesh::GetGroups()
 
     TPythonDump pydump; // to prevent dump at mesh creation
-    mesh = makeMesh( theMeshName );
+    mesh   = makeMesh( theMeshName );
     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
 
     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
 
-    TIDSortedElemSet elements;
-    if ( mesh_i &&
-      idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
+    if ( mesh_i )
     {
     {
-      translate(elements, theVector,false, theCopyGroups, & mesh_i->GetImpl());
+      scale(theObject, thePoint, theScaleFact,false, theCopyGroups, & mesh_i->GetImpl());
       mesh_i->CreateGroupServants();
     }
       mesh_i->CreateGroupServants();
     }
-    if ( !myIsPreviewMode ) {
-      pydump << mesh << " = " << this << ".TranslateObjectMakeMesh( "
-             << theObject     << ", "
-             << theVector     << ", "
-             << theCopyGroups << ", '"
-             << theMeshName   << "' )";
-    }
+    if ( !myIsPreviewMode )
+      pydump << mesh << " = " << this << ".ScaleMakeMesh( "
+             << theObject            << ", "
+             << thePoint             << ", "
+             << TVar( theScaleFact ) << ", "
+             << theCopyGroups        << ", '"
+             << theMeshName          << "' )";
   }
 
   // dump "GetGroups"
   }
 
   // dump "GetGroups"
@@ -3955,953 +4050,1309 @@ SMESH_MeshEditor_i::TranslateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
   return mesh._retn();
 }
 
   return mesh._retn();
 }
 
-//=======================================================================
-//function : rotate
-//purpose  :
-//=======================================================================
+//================================================================================
+/*!
+ * \brief Make an offset mesh from a source 2D mesh
+ *  \param [inout] theObject - source mesh. New elements are added to this mesh
+ *         if \a theMeshName is empty.
+ *  \param [in] theValue - offset value
+ *  \param [in] theCopyGroups - to generate groups
+ *  \param [in] theMeshName - optional name of a new mesh
+ *  \param [out] theGroups - new groups
+ *  \return SMESH::SMESH_Mesh_ptr - the modified mesh
+ */
+//================================================================================
 
 
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::rotate(TIDSortedElemSet &        theElements,
-                           const SMESH::AxisStruct & theAxis,
-                           CORBA::Double             theAngle,
-                           CORBA::Boolean            theCopy,
-                           bool                      theMakeGroups,
-                           ::SMESH_Mesh*             theTargetMesh)
+SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::Offset( SMESH::SMESH_IDSource_ptr theObject,
+                                                  CORBA::Double             theValue,
+                                                  CORBA::Boolean            theCopyGroups,
+                                                  CORBA::Boolean            theCopyElements,
+                                                  const char*               theMeshName,
+                                                  SMESH::ListOfGroups_out   theGroups)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   initData();
 
-  if ( theTargetMesh )
-    theCopy = false;
+  SMESHDS_Mesh* aMeshDS = getMeshDS();
 
 
-  gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
-  gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
+  SMESH::SMESH_Mesh_var         mesh_var;
+  ::SMESH_MeshEditor::PGroupIDs groupIds;
 
 
-  gp_Trsf aTrsf;
-  aTrsf.SetRotation( gp_Ax1( P, V ), theAngle);
+  TPythonDump pyDump;
 
 
-  TIDSortedElemSet  copyElements;
-  TIDSortedElemSet* workElements = &theElements;
-  if ( myIsPreviewMode ) {
-    TPreviewMesh * tmpMesh = getPreviewMesh();
-    tmpMesh->Copy( theElements, copyElements );
-    if ( !theCopy && !theTargetMesh )
+  TIDSortedElemSet elements, copyElements;
+  if ( idSourceToSet( theObject, aMeshDS, elements, SMDSAbs_Face,
+                      /*emptyIfIsMesh=*/ !myIsPreviewMode ))
+  {
+    // mesh to modify
+    SMESH_Mesh* tgtMesh = 0;
+    if ( myIsPreviewMode )
     {
     {
-      TIDSortedElemSet elemsAround, elemsAroundCopy;
-      getElementsAround( theElements, getMeshDS(), elemsAround );
-      tmpMesh->Copy( elemsAround, elemsAroundCopy);
+      TPreviewMesh * tmpMesh = getPreviewMesh();
+      tgtMesh = tmpMesh;
+      tmpMesh->Copy( elements, copyElements );
+      elements.swap( copyElements );
+      theCopyGroups = false;
+      theCopyElements = false;
     }
     }
-    workElements = &copyElements;
-    theMakeGroups = false;
-  }
+    else
+    {
+      mesh_var =
+        *theMeshName ? makeMesh( theMeshName ) : SMESH::SMESH_Mesh::_duplicate( myMesh_i->_this() );
+      SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
+      tgtMesh = & mesh_i->GetImpl();
+    }
+    groupIds = getEditor().Offset( elements, theValue, tgtMesh,
+                                   theCopyGroups, theCopyElements, !myIsPreviewMode );
 
 
-  ::SMESH_MeshEditor::PGroupIDs groupIds =
-      getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
+    tgtMesh->GetMeshDS()->Modified();
+  }
 
 
-  if ( theCopy && !myIsPreviewMode)
+  if ( myIsPreviewMode )
   {
   {
-    if ( theTargetMesh )
-    {
-      theTargetMesh->GetMeshDS()->Modified();
-    }
-    else
+    //getPreviewMesh()->Remove( SMESHUtils::elemSetIterator( copyElements ));
+  }
+  else
+  {
+    theGroups = theCopyGroups ? getGroups( groupIds.get() ) : new SMESH::ListOfGroups;
+
+    if ( *theMeshName && mesh_var->NbFaces() == 0 )
     {
     {
-      myMesh->GetMeshDS()->Modified();
-      myMesh->SetIsModified( true );
+      // new mesh empty, remove it
+      SALOMEDS::Study_var          study = SMESH_Gen_i::getStudyServant();
+      SALOMEDS::StudyBuilder_var builder = study->NewBuilder();
+      SALOMEDS::SObject_wrap      meshSO = SMESH_Gen_i::ObjectToSObject( mesh_var );
+      builder->RemoveObjectWithChildren( meshSO );
+      THROW_SALOME_CORBA_EXCEPTION("Offset failed", SALOME::INTERNAL_ERROR);
     }
     }
+
+    // result of Offset() is a tuple (mesh, groups)
+    if ( mesh_var->_is_nil() ) pyDump << myMesh_i->_this() << ", ";
+    else                       pyDump << mesh_var          << ", ";
+    pyDump << theGroups << " = " << this << ".Offset( "
+           << theObject << ", "
+           << theValue << ", "
+           << theCopyGroups << ", "
+           << theCopyElements << ", "
+           << "'" << theMeshName<< "')";
   }
 
   }
 
-  return theMakeGroups ? getGroups(groupIds.get()) : 0;
+  return mesh_var._retn();
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return SMESH::SMESH_Mesh::_nil();
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : Rotate
+//function : findCoincidentNodes
 //purpose  :
 //=======================================================================
 
 //purpose  :
 //=======================================================================
 
-void SMESH_MeshEditor_i::Rotate(const SMESH::long_array & theIDsOfElements,
-                                const SMESH::AxisStruct & theAxis,
-                                CORBA::Double             theAngle,
-                                CORBA::Boolean            theCopy)
+void SMESH_MeshEditor_i::
+findCoincidentNodes (TIDSortedNodeSet &             Nodes,
+                     CORBA::Double                  Tolerance,
+                     SMESH::array_of_long_array_out GroupsOfNodes,
+                     CORBA::Boolean                 SeparateCornersAndMedium)
 {
 {
-  if (!myIsPreviewMode) {
-    TPythonDump() << this << ".Rotate( "
-                  << theIDsOfElements << ", "
-                  << theAxis          << ", "
-                  << TVar( theAngle ) << ", "
-                  << theCopy          << " )";
-  }
-  if (theIDsOfElements.length() > 0)
+  ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
+  getEditor().FindCoincidentNodes( Nodes, Tolerance, aListOfListOfNodes, SeparateCornersAndMedium );
+
+  GroupsOfNodes = new SMESH::array_of_long_array;
+  GroupsOfNodes->length( aListOfListOfNodes.size() );
+  ::SMESH_MeshEditor::TListOfListOfNodes::iterator llIt = aListOfListOfNodes.begin();
+  for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
   {
   {
-    TIDSortedElemSet elements;
-    arrayToSet(theIDsOfElements, getMeshDS(), elements);
-    rotate(elements,theAxis,theAngle,theCopy,false);
+    list< const SMDS_MeshNode* >& aListOfNodes = *llIt;
+    list< const SMDS_MeshNode* >::iterator lIt = aListOfNodes.begin();;
+    SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
+    aGroup.length( aListOfNodes.size() );
+    for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
+      aGroup[ j ] = (*lIt)->GetID();
   }
 }
 
 //=======================================================================
   }
 }
 
 //=======================================================================
-//function : RotateObject
+//function : FindCoincidentNodes
 //purpose  :
 //=======================================================================
 
 //purpose  :
 //=======================================================================
 
-void SMESH_MeshEditor_i::RotateObject(SMESH::SMESH_IDSource_ptr theObject,
-                                      const SMESH::AxisStruct & theAxis,
-                                      CORBA::Double             theAngle,
-                                      CORBA::Boolean            theCopy)
+void SMESH_MeshEditor_i::
+FindCoincidentNodes (CORBA::Double                  Tolerance,
+                     SMESH::array_of_long_array_out GroupsOfNodes,
+                     CORBA::Boolean                 SeparateCornersAndMedium)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  if ( !myIsPreviewMode ) {
-    TPythonDump() << this << ".RotateObject( "
-                  << theObject        << ", "
-                  << theAxis          << ", "
-                  << TVar( theAngle ) << ", "
-                  << theCopy          << " )";
-  }
-  TIDSortedElemSet elements;
-  bool emptyIfIsMesh = myIsPreviewMode ? false : true;
-  if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
-    rotate(elements,theAxis,theAngle,theCopy,false);
+  SMESH_TRY;
+  initData();
+
+  TIDSortedNodeSet nodes; // no input nodes
+  findCoincidentNodes( nodes, Tolerance, GroupsOfNodes, SeparateCornersAndMedium );
+
+  TPythonDump() << "coincident_nodes = " << this << ".FindCoincidentNodes( "
+                << Tolerance << ", "
+                << SeparateCornersAndMedium << " )";
+
+  SMESH_CATCH( SMESH::throwCorbaException );
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : RotateMakeGroups
+//function : FindCoincidentNodesOnPart
 //purpose  :
 //=======================================================================
 
 //purpose  :
 //=======================================================================
 
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::RotateMakeGroups(const SMESH::long_array& theIDsOfElements,
-                                     const SMESH::AxisStruct& theAxis,
-                                     CORBA::Double            theAngle)
+void SMESH_MeshEditor_i::
+FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr      theObject,
+                          CORBA::Double                  Tolerance,
+                          SMESH::array_of_long_array_out GroupsOfNodes,
+                          CORBA::Boolean                 SeparateCornersAndMedium)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+  SMESH_TRY;
+  initData();
 
 
-  SMESH::ListOfGroups * aGroups = 0;
-  if (theIDsOfElements.length() > 0)
+  TIDSortedNodeSet nodes;
+  prepareIdSource( theObject );
+  idSourceToNodeSet( theObject, getMeshDS(), nodes );
+
+  findCoincidentNodes( nodes, Tolerance, GroupsOfNodes, SeparateCornersAndMedium );
+
+  TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPart( "
+                << theObject <<", "
+                << Tolerance << ", "
+                << SeparateCornersAndMedium << " )";
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+}
+
+//================================================================================
+/*!
+ * \brief Finds nodes coincident with Tolerance within Objects excluding nodes within
+ *        ExceptSubMeshOrGroups
+ */
+//================================================================================
+
+void SMESH_MeshEditor_i::
+FindCoincidentNodesOnPartBut(const SMESH::ListOfIDSources&  theObjects,
+                             CORBA::Double                  theTolerance,
+                             SMESH::array_of_long_array_out theGroupsOfNodes,
+                             const SMESH::ListOfIDSources&  theExceptSubMeshOrGroups,
+                             CORBA::Boolean                 theSeparateCornersAndMedium)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH_TRY;
+  initData();
+
+  TIDSortedNodeSet nodes;
+  for ( CORBA::ULong i = 0; i < theObjects.length(); ++i )
   {
   {
-    TIDSortedElemSet elements;
-    arrayToSet(theIDsOfElements, getMeshDS(), elements);
-    aGroups = rotate(elements,theAxis,theAngle,true,true);
+    prepareIdSource( theObjects[i] );
+    idSourceToNodeSet( theObjects[i], getMeshDS(), nodes );
   }
   }
-  if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".RotateMakeGroups( "
-                << theIDsOfElements << ", "
-                << theAxis          << ", "
-                << TVar( theAngle ) << " )";
+  for ( CORBA::ULong i = 0; i < theExceptSubMeshOrGroups.length(); ++i )
+  {
+    if ( SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( theExceptSubMeshOrGroups[i],
+                                                              SMESH::NODE ))
+      while ( nodeIt->more() )
+        nodes.erase( cast2Node( nodeIt->next() ));
   }
   }
-  return aGroups;
+  findCoincidentNodes( nodes, theTolerance, theGroupsOfNodes, theSeparateCornersAndMedium );
+
+  TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPartBut( "
+                << theObjects <<", "
+                << theTolerance << ", "
+                << theExceptSubMeshOrGroups << ", "
+                << theSeparateCornersAndMedium << " )";
+
+  SMESH_CATCH( SMESH::throwCorbaException );
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : RotateObjectMakeGroups
+//function : MergeNodes
 //purpose  :
 //=======================================================================
 
 //purpose  :
 //=======================================================================
 
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::RotateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
-                                           const SMESH::AxisStruct&  theAxis,
-                                           CORBA::Double             theAngle)
+void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfNodes,
+                                     const SMESH::ListOfIDSources&     NodesToKeep,
+                                     CORBA::Boolean                    AvoidMakingHoles)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+  SMESH_TRY;
+  initData();
 
 
-  SMESH::ListOfGroups * aGroups = 0;
-  TIDSortedElemSet elements;
-  if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
-    aGroups = rotate(elements, theAxis, theAngle, true, true);
+  SMESHDS_Mesh* aMesh = getMeshDS();
 
 
-  if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".RotateObjectMakeGroups( "
-                << theObject        << ", "
-                << theAxis          << ", "
-                << TVar( theAngle ) << " )";
+  TPythonDump aTPythonDump;
+  aTPythonDump << this << ".MergeNodes([";
+
+  TIDSortedNodeSet setOfNodesToKeep;
+  for ( CORBA::ULong i = 0; i < NodesToKeep.length(); ++i )
+  {
+    prepareIdSource( NodesToKeep[i] );
+    if ( SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( NodesToKeep[i], SMESH::NODE ))
+      while ( nodeIt->more() )
+        setOfNodesToKeep.insert( setOfNodesToKeep.end(), cast2Node( nodeIt->next() ));
   }
   }
-  return aGroups;
+
+  ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
+  for ( CORBA::ULong i = 0; i < GroupsOfNodes.length(); i++ )
+  {
+    const SMESH::long_array& aNodeGroup = GroupsOfNodes[ i ];
+    aListOfListOfNodes.push_back( list< const SMDS_MeshNode* >() );
+    list< const SMDS_MeshNode* >& aListOfNodes = aListOfListOfNodes.back();
+    for ( CORBA::ULong j = 0; j < aNodeGroup.length(); j++ )
+    {
+      CORBA::Long index = aNodeGroup[ j ];
+      if ( const SMDS_MeshNode * node = aMesh->FindNode( index ))
+      {
+        if ( setOfNodesToKeep.count( node ))
+          aListOfNodes.push_front( node );
+        else
+          aListOfNodes.push_back( node );
+      }
+    }
+    if ( aListOfNodes.size() < 2 )
+      aListOfListOfNodes.pop_back();
+
+    if ( i > 0 ) aTPythonDump << ", ";
+    aTPythonDump << aNodeGroup;
+  }
+
+  getEditor().MergeNodes( aListOfListOfNodes, AvoidMakingHoles );
+
+  aTPythonDump << "], " << NodesToKeep << ", " << AvoidMakingHoles << ")";
+
+  declareMeshModified( /*isReComputeSafe=*/false );
+
+  SMESH_CATCH( SMESH::throwCorbaException );
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : RotateMakeMesh
+//function : FindEqualElements
 //purpose  :
 //=======================================================================
 
 //purpose  :
 //=======================================================================
 
-SMESH::SMESH_Mesh_ptr
-SMESH_MeshEditor_i::RotateMakeMesh(const SMESH::long_array& theIDsOfElements,
-                                   const SMESH::AxisStruct& theAxis,
-                                   CORBA::Double            theAngleInRadians,
-                                   CORBA::Boolean           theCopyGroups,
-                                   const char*              theMeshName)
+void SMESH_MeshEditor_i::FindEqualElements(const SMESH::ListOfIDSources&  theObjects,
+                                           const SMESH::ListOfIDSources&  theExceptObjects,
+                                           SMESH::array_of_long_array_out theGroupsOfElementsID)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  SMESH::SMESH_Mesh_var mesh;
-  SMESH_Mesh_i* mesh_i;
+  SMESH_TRY;
+  initData();
 
 
-  { // open new scope to dump "MakeMesh" command
-    // and then "GetGroups" using SMESH_Mesh::GetGroups()
+  theGroupsOfElementsID = new SMESH::array_of_long_array;
 
 
-    TPythonDump pydump; // to prevent dump at mesh creation
+  TIDSortedElemSet elems;
+  bool hasOkObject = false;
+  bool emptyIfIsMesh= ( theObjects.length() == 1 && theExceptObjects.length() == 0 );
 
 
-    mesh = makeMesh( theMeshName );
-    mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
+  for ( CORBA::ULong i = 0; i < theObjects.length(); ++i )
+  {
+    SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow( theObjects[i] );
+    if ( !( !group->_is_nil() && group->GetType() == SMESH::NODE ))
+      if ( idSourceToSet( theObjects[i], getMeshDS(), elems, SMDSAbs_All, emptyIfIsMesh ))
+        hasOkObject = true;
+  }
 
 
-    if ( mesh_i && theIDsOfElements.length() > 0 )
+  if ( hasOkObject )
+  {
+    for ( CORBA::ULong i = 0; i < theExceptObjects.length(); ++i )
     {
     {
-      TIDSortedElemSet elements;
-      arrayToSet(theIDsOfElements, getMeshDS(), elements);
-      rotate(elements, theAxis, theAngleInRadians,
-             false, theCopyGroups, & mesh_i->GetImpl());
-      mesh_i->CreateGroupServants();
+      if ( SMDS_ElemIteratorPtr elemIt = myMesh_i->GetElements( theExceptObjects[i], SMESH::ALL ))
+        while ( elemIt->more() )
+          elems.erase( elemIt->next() );
     }
     }
-    if ( !myIsPreviewMode ) {
-      pydump << mesh << " = " << this << ".RotateMakeMesh( "
-             << theIDsOfElements          << ", "
-             << theAxis                   << ", "
-             << TVar( theAngleInRadians ) << ", "
-             << theCopyGroups             << ", '"
-             << theMeshName               << "' )";
+
+    ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
+    getEditor().FindEqualElements( elems, aListOfListOfElementsID );
+
+    theGroupsOfElementsID->length( aListOfListOfElementsID.size() );
+
+    ::SMESH_MeshEditor::TListOfListOfElementsID::iterator arraysIt =
+        aListOfListOfElementsID.begin();
+    for (CORBA::Long j = 0; arraysIt != aListOfListOfElementsID.end(); ++arraysIt, ++j)
+    {
+      SMESH::long_array& aGroup = (*theGroupsOfElementsID)[ j ];
+      list<int>&      listOfIDs = *arraysIt;
+      aGroup.length( listOfIDs.size() );
+      list<int>::iterator idIt = listOfIDs.begin();
+      for (int k = 0; idIt != listOfIDs.end(); ++idIt, ++k )
+        aGroup[ k ] = *idIt;
     }
     }
-  }
 
 
-  // dump "GetGroups"
-  if (!myIsPreviewMode && mesh_i && theIDsOfElements.length() > 0 )
-    mesh_i->GetGroups();
+    TPythonDump() << "equal_elements = " << this << ".FindEqualElements( "
+                  << theObjects << ", "
+                  << theExceptObjects << " )";
+  }
 
 
-  return mesh._retn();
+  SMESH_CATCH( SMESH::throwCorbaException );
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : RotateObjectMakeMesh
+//function : MergeElements
 //purpose  :
 //=======================================================================
 
 //purpose  :
 //=======================================================================
 
-SMESH::SMESH_Mesh_ptr
-SMESH_MeshEditor_i::RotateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
-                                         const SMESH::AxisStruct&  theAxis,
-                                         CORBA::Double             theAngleInRadians,
-                                         CORBA::Boolean            theCopyGroups,
-                                         const char*               theMeshName)
+void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& theGroupsOfElementsID,
+                                       const SMESH::ListOfIDSources&     theElementsToKeep)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  SMESH::SMESH_Mesh_var mesh;
-  SMESH_Mesh_i* mesh_i;
+  SMESH_TRY;
+  initData();
 
 
-  {// open new scope to dump "MakeMesh" command
-   // and then "GetGroups" using SMESH_Mesh::GetGroups()
+  TPythonDump aTPythonDump;
+  aTPythonDump << this << ".MergeElements( [";
 
 
-    TPythonDump pydump; // to prevent dump at mesh creation
-    mesh = makeMesh( theMeshName );
-    mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
+  NCollection_Map< int > idsToKeep;
+  for ( CORBA::ULong i = 0; i < theElementsToKeep.length(); i++ )
+  {
+    if ( CORBA::is_nil( theElementsToKeep[i] ))
+      continue;
+    SMESH::array_of_ElementType_var elemTypes = theElementsToKeep[i]->GetTypes();
+    if ( elemTypes->length() == 1 && elemTypes[0] == SMESH::NODE )
+      continue;
+    SMESH::long_array_var elementsId = theElementsToKeep[i]->GetIDs();
+    for ( CORBA::ULong j = 0; j < elementsId->length(); ++j )
+      idsToKeep.Add( elementsId[ j ]);
+  }
 
 
-    TIDSortedElemSet elements;
-    if (mesh_i &&
-        idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
+  ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
+
+  for ( CORBA::ULong i = 0; i < theGroupsOfElementsID.length(); i++ )
+  {
+    const SMESH::long_array& anElemsIDGroup = theGroupsOfElementsID[ i ];
+    aListOfListOfElementsID.push_back( list< int >() );
+    list< int >& aListOfElemsID = aListOfListOfElementsID.back();
+    for ( CORBA::ULong j = 0; j < anElemsIDGroup.length(); j++ )
     {
     {
-      rotate(elements, theAxis, theAngleInRadians,
-             false, theCopyGroups, & mesh_i->GetImpl());
-      mesh_i->CreateGroupServants();
-    }
-    if ( !myIsPreviewMode ) {
-      pydump << mesh << " = " << this << ".RotateObjectMakeMesh( "
-             << theObject                 << ", "
-             << theAxis                   << ", "
-             << TVar( theAngleInRadians ) << ", "
-             << theCopyGroups             << ", '"
-             << theMeshName               << "' )";
+      CORBA::Long id = anElemsIDGroup[ j ];
+      if ( idsToKeep.Contains( id )) aListOfElemsID.push_front( id );
+      else                           aListOfElemsID.push_back( id );
     }
     }
+    if ( aListOfElemsID.size() < 2 )
+      aListOfListOfElementsID.pop_back();
+    if ( i > 0 ) aTPythonDump << ", ";
+    aTPythonDump << anElemsIDGroup;
   }
 
   }
 
-  // dump "GetGroups"
-  if (!myIsPreviewMode && mesh_i)
-    mesh_i->GetGroups();
+  getEditor().MergeElements(aListOfListOfElementsID);
 
 
-  return mesh._retn();
+  declareMeshModified( /*isReComputeSafe=*/true );
+
+  aTPythonDump << "], " << theElementsToKeep << " )";
+
+  SMESH_CATCH( SMESH::throwCorbaException );
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : scale
+//function : MergeEqualElements
 //purpose  :
 //=======================================================================
 
 //purpose  :
 //=======================================================================
 
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::scale(SMESH::SMESH_IDSource_ptr  theObject,
-                          const SMESH::PointStruct&  thePoint,
-                          const SMESH::double_array& theScaleFact,
-                          CORBA::Boolean             theCopy,
-                          bool                       theMakeGroups,
-                          ::SMESH_Mesh*              theTargetMesh)
+void SMESH_MeshEditor_i::MergeEqualElements()
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
   initData();
-  if ( theScaleFact.length() < 1 )
-    THROW_SALOME_CORBA_EXCEPTION("Scale factor not given", SALOME::BAD_PARAM);
-  if ( theScaleFact.length() == 2 )
-    THROW_SALOME_CORBA_EXCEPTION("Invalid nb of scale factors : 2", SALOME::BAD_PARAM);
 
 
-  if ( theTargetMesh )
-    theCopy = false;
+  getEditor().MergeEqualElements();
 
 
-  TIDSortedElemSet elements;
-  bool emptyIfIsMesh = myIsPreviewMode ? false : true;
-  if ( !idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
-    return 0;
+  declareMeshModified( /*isReComputeSafe=*/true );
 
 
-  double S[3] = {
-    theScaleFact[0],
-    (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[1],
-    (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[2],
-  };
-  double tol = std::numeric_limits<double>::max();
-  gp_Trsf aTrsf;
-  aTrsf.SetValues( S[0], 0,    0,    thePoint.x * (1-S[0]),
-                   0,    S[1], 0,    thePoint.y * (1-S[1]),
-                   0,    0,    S[2], thePoint.z * (1-S[2]),   tol, tol);
+  TPythonDump() << this << ".MergeEqualElements()";
 
 
-  TIDSortedElemSet  copyElements;
-  TIDSortedElemSet* workElements = &elements;
-  if ( myIsPreviewMode )
-  {
-    TPreviewMesh * tmpMesh = getPreviewMesh();
-    tmpMesh->Copy( elements, copyElements);
-    if ( !theCopy && !theTargetMesh )
-    {
-      TIDSortedElemSet elemsAround, elemsAroundCopy;
-      getElementsAround( elements, getMeshDS(), elemsAround );
-      tmpMesh->Copy( elemsAround, elemsAroundCopy);
-    }
-    workElements = & copyElements;
-    theMakeGroups = false;
-  }
+  SMESH_CATCH( SMESH::throwCorbaException );
+}
 
 
-  ::SMESH_MeshEditor::PGroupIDs groupIds =
-      getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
+//=============================================================================
+/*!
+ * Move the node to a given point
+ */
+//=============================================================================
 
 
-  if ( theCopy && !myIsPreviewMode )
+CORBA::Boolean SMESH_MeshEditor_i::MoveNode(CORBA::Long   NodeID,
+                                            CORBA::Double x,
+                                            CORBA::Double y,
+                                            CORBA::Double z)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH_TRY;
+  initData(/*deleteSearchers=*/false);
+
+  const SMDS_MeshNode * node = getMeshDS()->FindNode( NodeID );
+  if ( !node )
+    return false;
+
+  if ( theNodeSearcher )
+    theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
+
+  if ( myIsPreviewMode ) // make preview data
   {
   {
-    if ( theTargetMesh )
-    {
-      theTargetMesh->GetMeshDS()->Modified();
-    }
-    else
+    // in a preview mesh, make edges linked to a node
+    TPreviewMesh& tmpMesh = *getPreviewMesh();
+    TIDSortedElemSet linkedNodes;
+    ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
+    TIDSortedElemSet::iterator nIt = linkedNodes.begin();
+    SMDS_MeshNode *nodeCpy1 = tmpMesh.Copy(node);
+    for ( ; nIt != linkedNodes.end(); ++nIt )
     {
     {
-      myMesh->GetMeshDS()->Modified();
-      myMesh->SetIsModified( true );
+      SMDS_MeshNode *nodeCpy2 = tmpMesh.Copy ( cast2Node( *nIt ));
+      tmpMesh.GetMeshDS()->AddEdge(nodeCpy1, nodeCpy2);
     }
     }
+    // move copied node
+    if ( nodeCpy1 )
+      tmpMesh.GetMeshDS()->MoveNode(nodeCpy1, x, y, z);
+    // fill preview data
   }
   }
+  else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
+    theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
+  else
+    getMeshDS()->MoveNode(node, x, y, z);
 
 
-  return theMakeGroups ? getGroups(groupIds.get()) : 0;
-}
+  if ( !myIsPreviewMode )
+  {
+    // Update Python script
+    TPythonDump() << "isDone = " << this << ".MoveNode( "
+                  << NodeID << ", " << TVar(x) << ", " << TVar(y) << ", " << TVar(z) << " )";
+    declareMeshModified( /*isReComputeSafe=*/false );
+  }
 
 
-//=======================================================================
-//function : Scale
-//purpose  :
-//=======================================================================
+  SMESH_CATCH( SMESH::throwCorbaException );
 
 
-void SMESH_MeshEditor_i::Scale(SMESH::SMESH_IDSource_ptr  theObject,
-                               const SMESH::PointStruct&  thePoint,
-                               const SMESH::double_array& theScaleFact,
-                               CORBA::Boolean             theCopy)
-{
-  if ( !myIsPreviewMode ) {
-    TPythonDump() << this << ".Scale( "
-                  << theObject            << ", "
-                  << thePoint             << ", "
-                  << TVar( theScaleFact ) << ", "
-                  << theCopy              << " )";
-  }
-  scale(theObject, thePoint, theScaleFact, theCopy, false);
+  return true;
 }
 
 }
 
+//================================================================================
+/*!
+ * \brief Return ID of node closest to a given point
+ */
+//================================================================================
 
 
-//=======================================================================
-//function : ScaleMakeGroups
-//purpose  :
-//=======================================================================
-
-SMESH::ListOfGroups*
-SMESH_MeshEditor_i::ScaleMakeGroups(SMESH::SMESH_IDSource_ptr  theObject,
-                                    const SMESH::PointStruct&  thePoint,
-                                    const SMESH::double_array& theScaleFact)
+CORBA::Long SMESH_MeshEditor_i::FindNodeClosestTo(CORBA::Double x,
+                                                  CORBA::Double y,
+                                                  CORBA::Double z)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
+  SMESH_TRY;
+  theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
 
 
-  SMESH::ListOfGroups * aGroups = scale(theObject, thePoint, theScaleFact, true, true);
-  if (!myIsPreviewMode) {
-    DumpGroupsList(aPythonDump, aGroups);
-    aPythonDump << this << ".Scale("
-                << theObject            << ","
-                << thePoint             << ","
-                << TVar( theScaleFact ) << ",True,True)";
+  if ( !theNodeSearcher ) {
+    theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
   }
   }
-  return aGroups;
-}
+  gp_Pnt p( x,y,z );
+  if ( const SMDS_MeshNode* node = theNodeSearcher->FindClosestTo( p ))
+    return node->GetID();
 
 
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
 
 
-//=======================================================================
-//function : ScaleMakeMesh
-//purpose  :
-//=======================================================================
+//================================================================================
+/*!
+ * \brief If the given ID is a valid node ID (nodeID > 0), just move this node, else
+ * move the node closest to the point to point's location and return ID of the node
+ */
+//================================================================================
 
 
-SMESH::SMESH_Mesh_ptr
-SMESH_MeshEditor_i::ScaleMakeMesh(SMESH::SMESH_IDSource_ptr  theObject,
-                                  const SMESH::PointStruct&  thePoint,
-                                  const SMESH::double_array& theScaleFact,
-                                  CORBA::Boolean             theCopyGroups,
-                                  const char*                theMeshName)
+CORBA::Long SMESH_MeshEditor_i::MoveClosestNodeToPoint(CORBA::Double x,
+                                                       CORBA::Double y,
+                                                       CORBA::Double z,
+                                                       CORBA::Long   theNodeID)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  SMESH_Mesh_i* mesh_i;
-  SMESH::SMESH_Mesh_var mesh;
-  { // open new scope to dump "MakeMesh" command
-    // and then "GetGroups" using SMESH_Mesh::GetGroups()
+  SMESH_TRY;
+  // We keep theNodeSearcher until any mesh modification:
+  // 1) initData() deletes theNodeSearcher at any edition,
+  // 2) TSearchersDeleter - at any mesh compute event and mesh change
 
 
-    TPythonDump pydump; // to prevent dump at mesh creation
-    mesh = makeMesh( theMeshName );
-    mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
+  initData(/*deleteSearchers=*/false);
 
 
-    if ( mesh_i )
+  theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
+
+  int nodeID = theNodeID;
+  const SMDS_MeshNode* node = getMeshDS()->FindNode( nodeID );
+  if ( !node ) // preview moving node
+  {
+    if ( !theNodeSearcher ) {
+      theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
+    }
+    gp_Pnt p( x,y,z );
+    node = theNodeSearcher->FindClosestTo( p );
+  }
+  if ( node ) {
+    nodeID = node->GetID();
+    if ( myIsPreviewMode ) // make preview data
     {
     {
-      scale(theObject, thePoint, theScaleFact,false, theCopyGroups, & mesh_i->GetImpl());
-      mesh_i->CreateGroupServants();
+      // in a preview mesh, make edges linked to a node
+      TPreviewMesh tmpMesh = *getPreviewMesh();
+      TIDSortedElemSet linkedNodes;
+      ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
+      TIDSortedElemSet::iterator nIt = linkedNodes.begin();
+      for ( ; nIt != linkedNodes.end(); ++nIt )
+      {
+        SMDS_LinearEdge edge( node, cast2Node( *nIt ));
+        tmpMesh.Copy( &edge );
+      }
+      // move copied node
+      node = tmpMesh.GetMeshDS()->FindNode( nodeID );
+      if ( node )
+        tmpMesh.GetMeshDS()->MoveNode(node, x, y, z);
+      // fill preview data
+    }
+    else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
+    {
+      theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
+    }
+    else
+    {
+      getMeshDS()->MoveNode(node, x, y, z);
     }
     }
-    if ( !myIsPreviewMode )
-      pydump << mesh << " = " << this << ".ScaleMakeMesh( "
-             << theObject            << ", "
-             << thePoint             << ", "
-             << TVar( theScaleFact ) << ", "
-             << theCopyGroups        << ", '"
-             << theMeshName          << "' )";
   }
 
   }
 
-  // dump "GetGroups"
-  if (!myIsPreviewMode && mesh_i)
-    mesh_i->GetGroups();
+  if ( !myIsPreviewMode )
+  {
+    TPythonDump() << "nodeID = " << this
+                  << ".MoveClosestNodeToPoint( "<< x << ", " << y << ", " << z
+                  << ", " << nodeID << " )";
 
 
-  return mesh._retn();
-}
+    declareMeshModified( /*isReComputeSafe=*/false );
+  }
+
+  return nodeID;
 
 
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
 
 //=======================================================================
 
 //=======================================================================
-//function : FindCoincidentNodes
-//purpose  :
+/*!
+ * Return elements of given type where the given point is IN or ON.
+ *
+ * 'ALL' type means elements of any type excluding nodes
+ */
 //=======================================================================
 
 //=======================================================================
 
-void SMESH_MeshEditor_i::FindCoincidentNodes (CORBA::Double                  Tolerance,
-                                              SMESH::array_of_long_array_out GroupsOfNodes)
+SMESH::long_array* SMESH_MeshEditor_i::FindElementsByPoint(CORBA::Double      x,
+                                                           CORBA::Double      y,
+                                                           CORBA::Double      z,
+                                                           SMESH::ElementType type)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  initData();
-
-  ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
-  TIDSortedNodeSet nodes; // no input nodes
-  getEditor().FindCoincidentNodes( nodes, Tolerance, aListOfListOfNodes );
+  SMESH_TRY;
+  SMESH::long_array_var res = new SMESH::long_array;
+  vector< const SMDS_MeshElement* > foundElems;
 
 
-  GroupsOfNodes = new SMESH::array_of_long_array;
-  GroupsOfNodes->length( aListOfListOfNodes.size() );
-  ::SMESH_MeshEditor::TListOfListOfNodes::iterator llIt = aListOfListOfNodes.begin();
-  for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ ) {
-    list< const SMDS_MeshNode* >& aListOfNodes = *llIt;
-    list< const SMDS_MeshNode* >::iterator lIt = aListOfNodes.begin();;
-    SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
-    aGroup.length( aListOfNodes.size() );
-    for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
-      aGroup[ j ] = (*lIt)->GetID();
+  theSearchersDeleter.Set( myMesh );
+  if ( !theElementSearcher ) {
+    theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
   }
   }
-  TPythonDump() << "coincident_nodes = " << this << ".FindCoincidentNodes( "
-                << Tolerance << " )";
+  theElementSearcher->FindElementsByPoint( gp_Pnt( x,y,z ),
+                                           SMDSAbs_ElementType( type ),
+                                           foundElems);
+  res->length( foundElems.size() );
+  for ( size_t i = 0; i < foundElems.size(); ++i )
+    res[i] = foundElems[i]->GetID();
+
+  return res._retn();
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : FindCoincidentNodesOnPart
-//purpose  :
+//function : FindAmongElementsByPoint
+//purpose  : Searching among the given elements, return elements of given type 
+//           where the given point is IN or ON.
+//           'ALL' type means elements of any type excluding nodes
 //=======================================================================
 //=======================================================================
-void SMESH_MeshEditor_i::FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr      theObject,
-                                                   CORBA::Double                  Tolerance,
-                                                   SMESH::array_of_long_array_out GroupsOfNodes)
-{
-  initData();
-
-  TIDSortedNodeSet nodes;
-  idSourceToNodeSet( theObject, getMeshDS(), nodes );
 
 
-  ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
-  if(!nodes.empty())
-    getEditor().FindCoincidentNodes( nodes, Tolerance, aListOfListOfNodes );
+SMESH::long_array*
+SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementIDs,
+                                             CORBA::Double             x,
+                                             CORBA::Double             y,
+                                             CORBA::Double             z,
+                                             SMESH::ElementType        type)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH_TRY;
+  SMESH::long_array_var res = new SMESH::long_array;
 
 
-  GroupsOfNodes = new SMESH::array_of_long_array;
-  GroupsOfNodes->length( aListOfListOfNodes.size() );
-  ::SMESH_MeshEditor::TListOfListOfNodes::iterator llIt = aListOfListOfNodes.begin();
-  for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
+  prepareIdSource( elementIDs );
+  if ( type != SMESH::NODE )
   {
   {
-    list< const SMDS_MeshNode* >& aListOfNodes = *llIt;
-    list< const SMDS_MeshNode* >::iterator lIt = aListOfNodes.begin();;
-    SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
-    aGroup.length( aListOfNodes.size() );
-    for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
-      aGroup[ j ] = (*lIt)->GetID();
+    SMESH::array_of_ElementType_var types = elementIDs->GetTypes();
+    if ( types->length() == 1 && // a part contains only nodes or 0D elements
+         ( types[0] == SMESH::NODE || types[0] == SMESH::ELEM0D || types[0] == SMESH::BALL) &&
+         type != types[0] ) // but search of elements of dim > 0
+      return res._retn();
   }
   }
-  TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPart( "
-                <<theObject<<", "
-                << Tolerance << " )";
-}
 
 
-//================================================================================
-/*!
- * \brief Finds nodes coinsident with Tolerance within Object excluding nodes within
- *        ExceptSubMeshOrGroups
- */
-//================================================================================
+  SMESH::SMESH_Mesh_var mesh = elementIDs->GetMesh();
+  SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
+  if ( mesh_i != myMesh_i )
+  {
+    SMESH::SMESH_MeshEditor_var editor=
+      myIsPreviewMode ? mesh_i->GetMeshEditPreviewer() : mesh_i->GetMeshEditor();
+    return editor->FindAmongElementsByPoint( elementIDs, x,y,z, type );
+  }
 
 
-void SMESH_MeshEditor_i::
-FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr      theObject,
-                             CORBA::Double                  theTolerance,
-                             SMESH::array_of_long_array_out theGroupsOfNodes,
-                             const SMESH::ListOfIDSources&  theExceptSubMeshOrGroups)
-{
-  initData();
+  if ( SMESH::DownCast<SMESH_Mesh_i*>( elementIDs )) // elementIDs is the whole mesh 
+    return FindElementsByPoint( x,y,z, type );
 
 
-  TIDSortedNodeSet nodes;
-  idSourceToNodeSet( theObject, getMeshDS(), nodes );
+  TIDSortedElemSet elements; // elems should live until FindElementsByPoint() finishes
 
 
-  for ( int i = 0; i < theExceptSubMeshOrGroups.length(); ++i )
+  theSearchersDeleter.Set( myMesh, getPartIOR( elementIDs, type ));
+  if ( !theElementSearcher )
   {
   {
-    TIDSortedNodeSet exceptNodes;
-    idSourceToNodeSet( theExceptSubMeshOrGroups[i], getMeshDS(), exceptNodes );
-    TIDSortedNodeSet::iterator avoidNode = exceptNodes.begin();
-    for ( ; avoidNode != exceptNodes.end(); ++avoidNode)
-      nodes.erase( *avoidNode );
+    // create a searcher from elementIDs
+    SMDS_ElemIteratorPtr elemIt;
+    if ( ! SMESH::DownCast<SMESH_Mesh_i*>( elementIDs ))
+    {
+      //prepareIdSource( elementIDs );
+      elemIt = myMesh_i->GetElements( elementIDs, type );
+      if ( !elemIt )
+        return res._retn();
+    }
+    theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemIt );
   }
   }
-  ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
-  if(!nodes.empty())
-    getEditor().FindCoincidentNodes( nodes, theTolerance, aListOfListOfNodes );
 
 
-  theGroupsOfNodes = new SMESH::array_of_long_array;
-  theGroupsOfNodes->length( aListOfListOfNodes.size() );
-  ::SMESH_MeshEditor::TListOfListOfNodes::iterator llIt = aListOfListOfNodes.begin();
-  for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
-  {
-    list< const SMDS_MeshNode* >& aListOfNodes = *llIt;
-    list< const SMDS_MeshNode* >::iterator lIt = aListOfNodes.begin();;
-    SMESH::long_array& aGroup = (*theGroupsOfNodes)[ i ];
-    aGroup.length( aListOfNodes.size() );
-    for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
-      aGroup[ j ] = (*lIt)->GetID();
-  }
-  TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPartBut( "
-                << theObject<<", "
-                << theTolerance << ", "
-                << theExceptSubMeshOrGroups << " )";
+  vector< const SMDS_MeshElement* > foundElems;
+
+  theElementSearcher->FindElementsByPoint( gp_Pnt( x,y,z ),
+                                           SMDSAbs_ElementType( type ),
+                                           foundElems);
+  res->length( foundElems.size() );
+  for ( size_t i = 0; i < foundElems.size(); ++i )
+    res[i] = foundElems[i]->GetID();
+
+  return res._retn();
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : MergeNodes
-//purpose  :
+//function : ProjectPoint
+//purpose  : Project a point to a mesh object.
+//           Return ID of an element of given type where the given point is projected
+//           and coordinates of the projection point.
+//           In the case if nothing found, return -1 and []
 //=======================================================================
 
 //=======================================================================
 
-void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfNodes)
+CORBA::Long SMESH_MeshEditor_i::ProjectPoint(CORBA::Double             x,
+                                             CORBA::Double             y,
+                                             CORBA::Double             z,
+                                             SMESH::ElementType        type,
+                                             SMESH::SMESH_IDSource_ptr meshObject,
+                                             SMESH::double_array_out   projecton)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  initData();
+  if ( CORBA::is_nil( meshObject ))
+    THROW_SALOME_CORBA_EXCEPTION("NULL meshObject", SALOME::BAD_PARAM);
 
 
-  SMESHDS_Mesh* aMesh = getMeshDS();
+  SMESH_TRY;
 
 
-  TPythonDump aTPythonDump;
-  aTPythonDump << this << ".MergeNodes([";
-  ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
-  for (int i = 0; i < GroupsOfNodes.length(); i++)
+  SMESH::SMESH_Mesh_var mesh = meshObject->GetMesh();
+  SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
+  if ( mesh_i != myMesh_i )
   {
   {
-    const SMESH::long_array& aNodeGroup = GroupsOfNodes[ i ];
-    aListOfListOfNodes.push_back( list< const SMDS_MeshNode* >() );
-    list< const SMDS_MeshNode* >& aListOfNodes = aListOfListOfNodes.back();
-    for ( int j = 0; j < aNodeGroup.length(); j++ )
+    SMESH::SMESH_MeshEditor_var editor=
+      myIsPreviewMode ? mesh_i->GetMeshEditPreviewer() : mesh_i->GetMeshEditor();
+    return editor->ProjectPoint( x,y,z, type, meshObject, projecton );
+  }
+
+
+  theSearchersDeleter.Set( myMesh, getPartIOR( meshObject, type ));
+  if ( !theElementSearcher )
+  {
+    // create a searcher from meshObject
+
+    SMDS_ElemIteratorPtr elemIt;
+    if ( ! SMESH::DownCast<SMESH_Mesh_i*>( meshObject ))
     {
     {
-      CORBA::Long index = aNodeGroup[ j ];
-      const SMDS_MeshNode * node = aMesh->FindNode(index);
-      if ( node )
-        aListOfNodes.push_back( node );
+      prepareIdSource( meshObject );
+      elemIt = myMesh_i->GetElements( meshObject, type );
+      if ( !elemIt )
+        return -1;
     }
     }
-    if ( aListOfNodes.size() < 2 )
-      aListOfListOfNodes.pop_back();
+    theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemIt );
+  }
 
 
-    if ( i > 0 ) aTPythonDump << ", ";
-    aTPythonDump << aNodeGroup;
+  const SMDS_MeshElement* elem = 0;
+  gp_XYZ pProj = theElementSearcher->Project( gp_Pnt( x,y,z ),
+                                              SMDSAbs_ElementType( type ),
+                                              &elem );
+
+  projecton = new SMESH::double_array();
+  if ( elem && !elem->IsNull() )
+  {
+    projecton->length( 3 );
+    projecton[0] = pProj.X();
+    projecton[1] = pProj.Y();
+    projecton[2] = pProj.Z();
+    return elem->GetID();
   }
   }
-  getEditor().MergeNodes( aListOfListOfNodes );
 
 
-  aTPythonDump <<  "])";
-  myMesh->GetMeshDS()->Modified();
-  myMesh->SetIsModified( true );
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return -1;
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : FindEqualElements
-//purpose  :
+//function : GetPointState
+//purpose  : Return point state in a closed 2D mesh in terms of TopAbs_State enumeration.
+//           TopAbs_UNKNOWN state means that either mesh is wrong or the analysis fails.
 //=======================================================================
 //=======================================================================
-void SMESH_MeshEditor_i::FindEqualElements(SMESH::SMESH_IDSource_ptr      theObject,
-                                           SMESH::array_of_long_array_out GroupsOfElementsID)
+
+CORBA::Short SMESH_MeshEditor_i::GetPointState(CORBA::Double x,
+                                               CORBA::Double y,
+                                               CORBA::Double z)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  initData();
+  SMESH_TRY;
+  theSearchersDeleter.Set( myMesh );
+  if ( !theElementSearcher ) {
+    theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
+  }
+  return CORBA::Short( theElementSearcher->GetPointState( gp_Pnt( x,y,z )));
 
 
-  SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow(theObject);
-  if ( !(!group->_is_nil() && group->GetType() == SMESH::NODE) )
-  {
-    TIDSortedElemSet elems;
-    idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true);
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
 
 
-    ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
-    getEditor().FindEqualElements( elems, aListOfListOfElementsID );
+//=======================================================================
+//function : IsManifold
+//purpose  : Check if a 2D mesh is manifold
+//=======================================================================
 
 
-    GroupsOfElementsID = new SMESH::array_of_long_array;
-    GroupsOfElementsID->length( aListOfListOfElementsID.size() );
+CORBA::Boolean SMESH_MeshEditor_i::IsManifold()
+  throw (SALOME::SALOME_Exception)
+{
+  bool isManifold = true;
 
 
-    ::SMESH_MeshEditor::TListOfListOfElementsID::iterator arraysIt =
-        aListOfListOfElementsID.begin();
-    for (CORBA::Long j = 0; arraysIt != aListOfListOfElementsID.end(); ++arraysIt, ++j)
-    {
-      SMESH::long_array& aGroup = (*GroupsOfElementsID)[ j ];
-      list<int>&      listOfIDs = *arraysIt;
-      aGroup.length( listOfIDs.size() );
-      list<int>::iterator idIt = listOfIDs.begin();
-      for (int k = 0; idIt != listOfIDs.end(); ++idIt, ++k )
-        aGroup[ k ] = *idIt;
-    }
+  SMESH_TRY;
+  SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
+  SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(),
+                                    foundFreeBordes,
+                                    /*closedOnly=*/true,
+                                    &isManifold );
+  SMESH_CATCH( SMESH::throwCorbaException );
 
 
-    TPythonDump() << "equal_elements = " << this << ".FindEqualElements( "
-                  <<theObject<<" )";
-  }
+  return isManifold;
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : MergeElements
-//purpose  :
+//function : IsCoherentOrientation2D
+//purpose  : Check if orientation of 2D elements is coherent
 //=======================================================================
 
 //=======================================================================
 
-void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& GroupsOfElementsID)
+CORBA::Boolean SMESH_MeshEditor_i::IsCoherentOrientation2D()
+  throw (SALOME::SALOME_Exception)
 {
 {
-  initData();
-
-  TPythonDump aTPythonDump;
-  aTPythonDump << this << ".MergeElements( [";
-
-  ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
-
-  for (int i = 0; i < GroupsOfElementsID.length(); i++) {
-    const SMESH::long_array& anElemsIDGroup = GroupsOfElementsID[ i ];
-    aListOfListOfElementsID.push_back( list< int >() );
-    list< int >& aListOfElemsID = aListOfListOfElementsID.back();
-    for ( int j = 0; j < anElemsIDGroup.length(); j++ ) {
-      CORBA::Long id = anElemsIDGroup[ j ];
-      aListOfElemsID.push_back( id );
-    }
-    if ( aListOfElemsID.size() < 2 )
-      aListOfListOfElementsID.pop_back();
-    if ( i > 0 ) aTPythonDump << ", ";
-    aTPythonDump << anElemsIDGroup;
-  }
+  bool isGoodOri = true;
 
 
-  getEditor().MergeElements(aListOfListOfElementsID);
-  myMesh->GetMeshDS()->Modified();
-  myMesh->SetIsModified( true );
+  SMESH_TRY;
+  SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
+  SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(),
+                                    foundFreeBordes,
+                                    /*closedOnly=*/true,
+                                    /*isManifold=*/0,
+                                    &isGoodOri);
+  SMESH_CATCH( SMESH::throwCorbaException );
 
 
-  aTPythonDump << "] )";
+  return isGoodOri;
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : MergeEqualElements
-//purpose  :
+//function : Get1DBranches
+//purpose  : Partition given 1D elements into groups of contiguous edges.
+//           A node where number of meeting edges != 2 is a group end.
+//           An optional startNode is used to orient groups it belongs to.
+//return   : a list of edge groups and a list of corresponding node groups.
+//           If a group is closed, the first and last nodes of the group are same.
 //=======================================================================
 
 //=======================================================================
 
-void SMESH_MeshEditor_i::MergeEqualElements()
+SMESH::array_of_long_array*
+SMESH_MeshEditor_i::Get1DBranches( SMESH::SMESH_IDSource_ptr      theEdges,
+                                   CORBA::Long                    theStartNode,
+                                   SMESH::array_of_long_array_out theNodeGroups )
+  throw (SALOME::SALOME_Exception)
 {
 {
-  initData();
+  if ( CORBA::is_nil( theEdges ))
+    THROW_SALOME_CORBA_EXCEPTION("Get1DBranches(): NULL group given", SALOME::BAD_PARAM);
 
 
-  getEditor().MergeEqualElements();
+  SMESH::array_of_long_array_var edgeGroupArray = new SMESH::array_of_long_array;
+  theNodeGroups = new SMESH::array_of_long_array;
 
 
-  myMesh->GetMeshDS()->Modified();
+  SMESH_TRY;
 
 
-  TPythonDump() << this << ".MergeEqualElements()";
+  prepareIdSource( theEdges );
+
+  SMESH_MeshAlgos::TElemGroupVector edgeBranches;
+  SMESH_MeshAlgos::TNodeGroupVector nodeBranches;
+  SMESH_MeshAlgos::Get1DBranches( SMESH_Mesh_i::GetElements( theEdges, SMESH::EDGE ),
+                                  edgeBranches,
+                                  nodeBranches,
+                                  getMeshDS()->FindNode( theStartNode ));
+
+  edgeGroupArray->length( edgeBranches.size() );
+  for ( size_t iG = 0; iG < edgeBranches.size(); ++iG )
+  {
+    edgeGroupArray[ iG ].length( edgeBranches[ iG ].size() );
+    for ( size_t i = 0; i < edgeBranches[ iG ].size(); ++i )
+      edgeGroupArray[ iG ][ i ] = edgeBranches[ iG ][ i ]->GetID();
+  }
+
+  theNodeGroups->length( nodeBranches.size() );
+  for ( size_t iG = 0; iG < nodeBranches.size(); ++iG )
+  {
+    theNodeGroups[ iG ].length( nodeBranches[ iG ].size() );
+    for ( size_t i = 0; i < nodeBranches[ iG ].size(); ++i )
+      theNodeGroups[ iG ][ i ] = nodeBranches[ iG ][ i ]->GetID();
+  }
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+
+  return edgeGroupArray._retn();
 }
 
 }
 
-//=============================================================================
-/*!
- * Move the node to a given point
- */
-//=============================================================================
+//=======================================================================
+//function : FindSharpEdges
+//purpose  : Return sharp edges of faces and non-manifold ones. Optionally add existing edges.
+//=======================================================================
 
 
-CORBA::Boolean SMESH_MeshEditor_i::MoveNode(CORBA::Long   NodeID,
-                                            CORBA::Double x,
-                                            CORBA::Double y,
-                                            CORBA::Double z)
+SMESH::ListOfEdges* SMESH_MeshEditor_i::FindSharpEdges(CORBA::Double  theAngle,
+                                                       CORBA::Boolean theAddExisting)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  initData(/*deleteSearchers=*/false);
-
-  const SMDS_MeshNode * node = getMeshDS()->FindNode( NodeID );
-  if ( !node )
-    return false;
+  SMESH::ListOfEdges_var resultEdges = new SMESH::ListOfEdges;
+  SMESH_TRY;
 
 
-  if ( theNodeSearcher )
-    theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
+  initData();
 
 
-  if ( myIsPreviewMode ) // make preview data
+  std::vector< SMESH_MeshAlgos::Edge > edges =
+    SMESH_MeshAlgos::FindSharpEdges( getMeshDS(), theAngle, theAddExisting );
+
+  if ( myIsPreviewMode ) // fill a preview mesh with edges
   {
   {
-    // in a preview mesh, make edges linked to a node
-    TPreviewMesh& tmpMesh = *getPreviewMesh();
-    TIDSortedElemSet linkedNodes;
-    ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
-    TIDSortedElemSet::iterator nIt = linkedNodes.begin();
-    SMDS_MeshNode *nodeCpy1 = tmpMesh.Copy(node);
-    for ( ; nIt != linkedNodes.end(); ++nIt )
+    TPreviewMesh* mesh = getPreviewMesh( SMDSAbs_Edge );
+    SMDS_Mesh*  meshDS = mesh->GetMeshDS();
+    for ( size_t i = 0; i < edges.size(); ++i )
     {
     {
-      SMDS_MeshNode *nodeCpy2 = tmpMesh.Copy ( cast2Node( *nIt ));
-      tmpMesh.GetMeshDS()->AddEdge(nodeCpy1, nodeCpy2);
+      SMESH_NodeXYZ xyz1( edges[i]._node1), xyz2( edges[i]._node2);
+      SMDS_MeshNode* n1 = meshDS->AddNode( xyz1.X(), xyz1.Y(), xyz1.Z() );
+      SMDS_MeshNode* n2 = meshDS->AddNode( xyz2.X(), xyz2.Y(), xyz2.Z() );
+      if ( edges[i]._medium )
+      {
+        xyz1.Set( edges[i]._medium );
+        SMDS_MeshNode* nm = meshDS->AddNode( xyz1.X(), xyz1.Y(), xyz1.Z() );
+        mesh->GetMeshDS()->AddEdge( n1, n2, nm );
+      }
+      else
+      {
+        mesh->GetMeshDS()->AddEdge( n1, n2 );
+      }
     }
     }
-    // move copied node
-    if ( nodeCpy1 )
-      tmpMesh.GetMeshDS()->MoveNode(nodeCpy1, x, y, z);
-    // fill preview data
   }
   }
-  else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
-    theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
   else
   else
-    getMeshDS()->MoveNode(node, x, y, z);
-
-  if ( !myIsPreviewMode )
   {
   {
-    // Update Python script
-    TPythonDump() << "isDone = " << this << ".MoveNode( "
-                  << NodeID << ", " << TVar(x) << ", " << TVar(y) << ", " << TVar(z) << " )";
-    myMesh->GetMeshDS()->Modified();
-    myMesh->SetIsModified( true );
+    resultEdges->length( edges.size() );
+    for ( size_t i = 0; i < edges.size(); ++i )
+    {
+      resultEdges[ i ].node1  = edges[i]._node1->GetID();
+      resultEdges[ i ].node2  = edges[i]._node2->GetID();
+      resultEdges[ i ].medium = edges[i]._medium ? edges[i]._medium->GetID() : 0;
+    }
   }
   }
-
-  return true;
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return resultEdges._retn();
 }
 
 }
 
-//================================================================================
-/*!
- * \brief Return ID of node closest to a given point
- */
-//================================================================================
+//=======================================================================
+//function : FindFreeBorders
+//purpose  : Returns all or only closed FreeBorder's.
+//=======================================================================
 
 
-CORBA::Long SMESH_MeshEditor_i::FindNodeClosestTo(CORBA::Double x,
-                                                  CORBA::Double y,
-                                                  CORBA::Double z)
+SMESH::ListOfFreeBorders* SMESH_MeshEditor_i::FindFreeBorders(CORBA::Boolean closedOnly)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
+  SMESH::ListOfFreeBorders_var resBorders = new SMESH::ListOfFreeBorders;
+  SMESH_TRY;
 
 
-  if ( !theNodeSearcher ) {
-    theNodeSearcher = myEditor.GetNodeSearcher();
+  SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
+  SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(), foundFreeBordes, closedOnly );
+
+  resBorders->length( foundFreeBordes.size() );
+  for ( size_t i = 0; i < foundFreeBordes.size(); ++i )
+  {
+    const SMESH_MeshAlgos::TFreeBorder& bordNodes = foundFreeBordes[i];
+    SMESH::FreeBorder&                    bordOut = resBorders[i];
+    bordOut.nodeIDs.length( bordNodes.size() );
+    for ( size_t iN = 0; iN < bordNodes.size(); ++iN )
+      bordOut.nodeIDs[ iN ] = bordNodes[ iN ]->GetID();
   }
   }
-  gp_Pnt p( x,y,z );
-  if ( const SMDS_MeshNode* node = theNodeSearcher->FindClosestTo( p ))
-    return node->GetID();
 
 
-  return 0;
+  SMESH_CATCH( SMESH::throwCorbaException );
+
+  return resBorders._retn();
 }
 
 }
 
-//================================================================================
-/*!
- * \brief If the given ID is a valid node ID (nodeID > 0), just move this node, else
- * move the node closest to the point to point's location and return ID of the node
- */
-//================================================================================
+//=======================================================================
+//function : FillHole
+//purpose  : Fill with 2D elements a hole defined by a FreeBorder.
+//=======================================================================
 
 
-CORBA::Long SMESH_MeshEditor_i::MoveClosestNodeToPoint(CORBA::Double x,
-                                                       CORBA::Double y,
-                                                       CORBA::Double z,
-                                                       CORBA::Long   theNodeID)
+SMESH::SMESH_Group_ptr 
+SMESH_MeshEditor_i::FillHole(const SMESH::FreeBorder& theHole,
+                             const char*              theGroupName)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  // We keep theNodeSearcher until any mesh modification:
-  // 1) initData() deletes theNodeSearcher at any edition,
-  // 2) TSearchersDeleter - at any mesh compute event and mesh change
-
-  initData(/*deleteSearchers=*/false);
+  initData();
 
 
-  theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
+  if ( theHole.nodeIDs.length() < 4 )
+    THROW_SALOME_CORBA_EXCEPTION("A hole should be bound by at least 3 nodes", SALOME::BAD_PARAM);
+  if ( theHole.nodeIDs[0] != theHole.nodeIDs[ theHole.nodeIDs.length()-1 ] )
+    THROW_SALOME_CORBA_EXCEPTION("Not closed hole boundary. "
+                                 "First and last nodes must be same", SALOME::BAD_PARAM);
 
 
-  int nodeID = theNodeID;
-  const SMDS_MeshNode* node = getMeshDS()->FindNode( nodeID );
-  if ( !node ) // preview moving node
+  SMESH_MeshAlgos::TFreeBorder bordNodes;
+  bordNodes.resize( theHole.nodeIDs.length() );
+  for ( size_t iN = 0; iN < theHole.nodeIDs.length(); ++iN )
   {
   {
-    if ( !theNodeSearcher ) {
-      theNodeSearcher = myEditor.GetNodeSearcher();
-    }
-    gp_Pnt p( x,y,z );
-    node = theNodeSearcher->FindClosestTo( p );
+    bordNodes[ iN ] = getMeshDS()->FindNode( theHole.nodeIDs[ iN ]);
+    if ( !bordNodes[ iN ] )
+      THROW_SALOME_CORBA_EXCEPTION(SMESH_Comment("Node #") << theHole.nodeIDs[ iN ]
+                                   << " does not exist", SALOME::BAD_PARAM);
   }
   }
-  if ( node ) {
-    nodeID = node->GetID();
-    if ( myIsPreviewMode ) // make preview data
+
+  SMESH_TRY;
+
+  // prepare a preview mesh
+  MeshEditor_I::TPreviewMesh* previewMesh = 0;
+  SMDS_Mesh* meshDS = getMeshDS();
+  if ( myIsPreviewMode )
+  {
+    // copy faces sharing nodes of theHole
+    TIDSortedElemSet holeFaces;
+    previewMesh = getPreviewMesh( SMDSAbs_Face );
+    for ( size_t i = 0; i < bordNodes.size(); ++i )
     {
     {
-      // in a preview mesh, make edges linked to a node
-      TPreviewMesh tmpMesh = *getPreviewMesh();
-      TIDSortedElemSet linkedNodes;
-      ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
-      TIDSortedElemSet::iterator nIt = linkedNodes.begin();
-      for ( ; nIt != linkedNodes.end(); ++nIt )
+      SMDS_ElemIteratorPtr fIt = bordNodes[i]->GetInverseElementIterator( SMDSAbs_Face );
+      while ( fIt->more() )
       {
       {
-        SMDS_LinearEdge edge( node, cast2Node( *nIt ));
-        tmpMesh.Copy( &edge );
+        const SMDS_MeshElement* face = fIt->next();
+        if ( holeFaces.insert( face ).second )
+          previewMesh->Copy( face );
       }
       }
-      // move copied node
-      node = tmpMesh.GetMeshDS()->FindNode( nodeID );
-      if ( node )
-        tmpMesh.GetMeshDS()->MoveNode(node, x, y, z);
-      // fill preview data
-    }
-    else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
-    {
-      theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
-    }
-    else
-    {
-      getMeshDS()->MoveNode(node, x, y, z);
+      bordNodes[i] = previewMesh->GetMeshDS()->FindNode( bordNodes[i]->GetID() );
+      ASSERT( bordNodes[i] );
     }
     }
+    meshDS = previewMesh->GetMeshDS();
   }
 
   }
 
-  if ( !myIsPreviewMode )
+  // fill the hole
+  std::vector<const SMDS_MeshElement*> newFaces;
+  SMESH_MeshAlgos::FillHole( bordNodes, *meshDS, newFaces );
+
+  if ( myIsPreviewMode )
   {
   {
-    TPythonDump() << "nodeID = " << this
-                  << ".MoveClosestNodeToPoint( "<< x << ", " << y << ", " << z
-                  << ", " << nodeID << " )";
+    // show new faces
+    previewMesh->Clear();
+    for ( size_t i = 0; i < newFaces.size(); ++i )
+      previewMesh->Copy( newFaces[i] );
+  }
+  else
+  {
+    // return new faces via a group
+    SMESH::SMESH_Group_var group;
+    if ( theGroupName && theGroupName[0] && !newFaces.empty() )
+    {
+      SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
+      for ( CORBA::ULong i = 0; i < groups->length(); ++i )
+      {
+        SMESH::SMESH_GroupBase_var g = groups[ i ];
+        if ( g->GetType() != SMESH::FACE ) continue;
+        SMESH::SMESH_Group_var standalone = SMESH::SMESH_Group::_narrow( g );
+        if ( standalone->_is_nil() ) continue;
+        CORBA::String_var name = g->GetName();
+        if ( strcmp( theGroupName, name.in() ) == 0 )
+        {
+          group = standalone;
+          break;
+        }
+      }
+      if ( group->_is_nil() )
+        group = myMesh_i->CreateGroup( SMESH::FACE, theGroupName );
 
 
-    myMesh->GetMeshDS()->Modified();
-    myMesh->SetIsModified( true );
+      if ( !group->_is_nil() )
+      {
+        SMESH_GroupBase_i * grpI = SMESH::DownCast< SMESH_GroupBase_i* >( group );
+        SMESHDS_Group*     grpDS = static_cast< SMESHDS_Group* >( grpI->GetGroupDS() );
+        for ( size_t i = 0; i < newFaces.size(); ++i )
+          grpDS->Add( newFaces[ i ]);
+      }
+    }
+
+    // fill LastCreated
+    getEditor().ClearLastCreated();
+    SMESH_SequenceOfElemPtr& aSeq =
+      const_cast<SMESH_SequenceOfElemPtr&>( getEditor().GetLastCreatedElems() );
+    aSeq.swap( newFaces );
+
+    TPythonDump pyDump;
+    if ( group->_is_nil() ) pyDump << "_group = ";
+    else                    pyDump << group << " = ";
+    pyDump << this << ".FillHole( SMESH.FreeBorder(" << theHole.nodeIDs << " ))";
+
+    return group._retn();
   }
 
   }
 
-  return nodeID;
+  SMESH_CATCH( SMESH::throwCorbaException );
+
+  return SMESH::SMESH_Group::_nil();
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-/*!
- * Return elements of given type where the given point is IN or ON.
- *
- * 'ALL' type means elements of any type excluding nodes
- */
+//function : convError
+//purpose  :
 //=======================================================================
 
 //=======================================================================
 
-SMESH::long_array* SMESH_MeshEditor_i::FindElementsByPoint(CORBA::Double      x,
-                                                           CORBA::Double      y,
-                                                           CORBA::Double      z,
-                                                           SMESH::ElementType type)
-{
-  SMESH::long_array_var res = new SMESH::long_array;
-  vector< const SMDS_MeshElement* > foundElems;
+#define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
 
 
-  theSearchersDeleter.Set( myMesh );
-  if ( !theElementSearcher ) {
-    theElementSearcher = myEditor.GetElementSearcher();
+static SMESH::SMESH_MeshEditor::Sew_Error convError( const::SMESH_MeshEditor::Sew_Error e )
+{
+  switch ( e ) {
+    RETCASE( SEW_OK );
+    RETCASE( SEW_BORDER1_NOT_FOUND );
+    RETCASE( SEW_BORDER2_NOT_FOUND );
+    RETCASE( SEW_BOTH_BORDERS_NOT_FOUND );
+    RETCASE( SEW_BAD_SIDE_NODES );
+    RETCASE( SEW_VOLUMES_TO_SPLIT );
+    RETCASE( SEW_DIFF_NB_OF_ELEMENTS );
+    RETCASE( SEW_TOPO_DIFF_SETS_OF_ELEMENTS );
+    RETCASE( SEW_BAD_SIDE1_NODES );
+    RETCASE( SEW_BAD_SIDE2_NODES );
+    RETCASE( SEW_INTERNAL_ERROR );
   }
   }
-  theElementSearcher->FindElementsByPoint( gp_Pnt( x,y,z ),
-                                           SMDSAbs_ElementType( type ),
-                                           foundElems);
-  res->length( foundElems.size() );
-  for ( int i = 0; i < foundElems.size(); ++i )
-    res[i] = foundElems[i]->GetID();
-
-  if ( !myIsPreviewMode ) // call from tui
-    TPythonDump() << "res = " << this << ".FindElementsByPoint( "
-                  << x << ", "
-                  << y << ", "
-                  << z << ", "
-                  << type << " )";
-
-  return res._retn();
+  return SMESH::SMESH_MeshEditor::SEW_OK;
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : FindAmongElementsByPoint
-//purpose  : Searching among the given elements, return elements of given type 
-//           where the given point is IN or ON.
-//           'ALL' type means elements of any type excluding nodes
+/*!
+ * Returns groups of FreeBorder's coincident within the given tolerance.
+ * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent
+ * to free borders being compared is used.
+ */
 //=======================================================================
 
 //=======================================================================
 
-SMESH::long_array*
-SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementIDs,
-                                             CORBA::Double             x,
-                                             CORBA::Double             y,
-                                             CORBA::Double             z,
-                                             SMESH::ElementType        type)
+SMESH::CoincidentFreeBorders*
+SMESH_MeshEditor_i::FindCoincidentFreeBorders(CORBA::Double tolerance)
 {
 {
-  SMESH::long_array_var res = new SMESH::long_array;
-  
-  SMESH::array_of_ElementType_var types = elementIDs->GetTypes();
-  if ( types->length() == 1 && // a part contains only nodes or 0D elements
-       ( types[0] == SMESH::NODE || types[0] == SMESH::ELEM0D || types[0] == SMESH::BALL) &&
-       type != types[0] ) // but search of elements of dim > 0
-    return res._retn();
+  SMESH::CoincidentFreeBorders_var aCFB = new SMESH::CoincidentFreeBorders;
 
 
-  if ( SMESH::DownCast<SMESH_Mesh_i*>( elementIDs )) // elementIDs is the whole mesh 
-    return FindElementsByPoint( x,y,z, type );
+  SMESH_TRY;
 
 
-  TIDSortedElemSet elements; // elems should live until FindElementsByPoint() finishes
+  SMESH_MeshAlgos::CoincidentFreeBorders cfb;
+  SMESH_MeshAlgos::FindCoincidentFreeBorders( *getMeshDS(), tolerance, cfb );
 
 
-  theSearchersDeleter.Set( myMesh, getPartIOR( elementIDs, type ));
-  if ( !theElementSearcher )
+  // copy free borders
+  aCFB->borders.length( cfb._borders.size() );
+  for ( size_t i = 0; i < cfb._borders.size(); ++i )
   {
   {
-    // create a searcher from elementIDs
-    SMESH::SMESH_Mesh_var mesh = elementIDs->GetMesh();
-    SMESHDS_Mesh* meshDS = SMESH::DownCast<SMESH_Mesh_i*>( mesh )->GetImpl().GetMeshDS();
-
-    if ( !idSourceToSet( elementIDs, meshDS, elements,
-                         SMDSAbs_ElementType(type), /*emptyIfIsMesh=*/true))
-      return res._retn();
-
-    typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
-    SMDS_ElemIteratorPtr elemsIt( new TIter( elements.begin(), elements.end() ));
-
-    theElementSearcher = myEditor.GetElementSearcher(elemsIt);
+    SMESH_MeshAlgos::TFreeBorder& nodes = cfb._borders[i];
+    SMESH::FreeBorder&             aBRD = aCFB->borders[i];
+    aBRD.nodeIDs.length( nodes.size() );
+    for ( size_t iN = 0; iN < nodes.size(); ++iN )
+      aBRD.nodeIDs[ iN ] = nodes[ iN ]->GetID();
   }
 
   }
 
-  vector< const SMDS_MeshElement* > foundElems;
-
-  theElementSearcher->FindElementsByPoint( gp_Pnt( x,y,z ),
-                                           SMDSAbs_ElementType( type ),
-                                           foundElems);
-  res->length( foundElems.size() );
-  for ( int i = 0; i < foundElems.size(); ++i )
-    res[i] = foundElems[i]->GetID();
+  // copy coincident parts
+  aCFB->coincidentGroups.length( cfb._coincidentGroups.size() );
+  for ( size_t i = 0; i < cfb._coincidentGroups.size(); ++i )
+  {
+    SMESH_MeshAlgos::TCoincidentGroup& grp = cfb._coincidentGroups[i];
+    SMESH::FreeBordersGroup&          aGRP = aCFB->coincidentGroups[i];
+    aGRP.length( grp.size() );
+    for ( size_t iP = 0; iP < grp.size(); ++iP )
+    {
+      SMESH_MeshAlgos::TFreeBorderPart& part = grp[ iP ];
+      SMESH::FreeBorderPart&           aPART = aGRP[ iP ];
+      aPART.border   = part._border;
+      aPART.node1    = part._node1;
+      aPART.node2    = part._node2;
+      aPART.nodeLast = part._nodeLast;
+    }
+  }
+  SMESH_CATCH( SMESH::doNothing );
 
 
-  if ( !myIsPreviewMode ) // call from tui
-    TPythonDump() << "res = " << this << ".FindAmongElementsByPoint( "
-                  << elementIDs << ", "
-                  << x << ", "
-                  << y << ", "
-                  << z << ", "
-                  << type << " )";
+  TPythonDump() << "CoincidentFreeBorders = "
+                << this << ".FindCoincidentFreeBorders( " << tolerance << " )";
 
 
-  return res._retn();
-  
+  return aCFB._retn();
 }
 }
+
 //=======================================================================
 //=======================================================================
-//function : GetPointState
-//purpose  : Return point state in a closed 2D mesh in terms of TopAbs_State enumeration.
-//           TopAbs_UNKNOWN state means that either mesh is wrong or the analysis fails.
+/*!
+ * Sew FreeBorder's of each group
+ */
 //=======================================================================
 
 //=======================================================================
 
-CORBA::Short SMESH_MeshEditor_i::GetPointState(CORBA::Double x,
-                                               CORBA::Double y,
-                                               CORBA::Double z)
+CORBA::Short SMESH_MeshEditor_i::
+SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders,
+                         CORBA::Boolean                      createPolygons,
+                         CORBA::Boolean                      createPolyhedra)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  theSearchersDeleter.Set( myMesh );
-  if ( !theElementSearcher ) {
-    theElementSearcher = myEditor.GetElementSearcher();
+  CORBA::Short nbSewed = 0;
+
+  SMESH_MeshAlgos::TFreeBorderVec groups;
+  SMESH_MeshAlgos::TFreeBorder    borderNodes; // triples of nodes for every FreeBorderPart
+
+  // check the input and collect nodes
+  for ( CORBA::ULong i = 0; i < freeBorders.coincidentGroups.length(); ++i )
+  {
+    borderNodes.clear();
+    const SMESH::FreeBordersGroup& aGRP = freeBorders.coincidentGroups[ i ];
+    for ( CORBA::ULong iP = 0; iP < aGRP.length(); ++iP )
+    {
+      const SMESH::FreeBorderPart& aPART = aGRP[ iP ];
+      if ( aPART.border < 0 || aPART.border >= (int) freeBorders.borders.length() )
+        THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::border index", SALOME::BAD_PARAM);
+
+      const SMESH::FreeBorder& aBRD = freeBorders.borders[ aPART.border ];
+
+      if ( aPART.node1 < 0 || aPART.node1 > (int) aBRD.nodeIDs.length() )
+        THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::node1", SALOME::BAD_PARAM);
+      if ( aPART.node2 < 0 || aPART.node2 > (int) aBRD.nodeIDs.length() )
+        THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::node2", SALOME::BAD_PARAM);
+      if ( aPART.nodeLast < 0 || aPART.nodeLast > (int) aBRD.nodeIDs.length() )
+        THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::nodeLast", SALOME::BAD_PARAM);
+
+      // do not keep these nodes for further sewing as nodes can be removed by the sewing
+      const SMDS_MeshNode* n1 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node1    ]);
+      const SMDS_MeshNode* n2 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node2    ]);
+      const SMDS_MeshNode* n3 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.nodeLast ]);
+      if ( !n1)
+        THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node1", SALOME::BAD_PARAM);
+      if ( !n2 )
+        THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node2", SALOME::BAD_PARAM);
+      if ( !n3 )
+        THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::nodeLast", SALOME::BAD_PARAM);
+
+      borderNodes.push_back( n1 );
+      borderNodes.push_back( n2 );
+      borderNodes.push_back( n3 );
+    }
+    groups.push_back( borderNodes );
   }
   }
-  return CORBA::Short( theElementSearcher->GetPointState( gp_Pnt( x,y,z )));
-}
 
 
-//=======================================================================
-//function : convError
-//purpose  :
-//=======================================================================
+  // SewFreeBorder() can merge nodes, thus nodes stored in 'groups' can become dead;
+  // to get nodes that replace other nodes during merge we create 0D elements
+  // on each node and MergeNodes() will replace underlying nodes of 0D elements by
+  // new ones.
+
+  vector< const SMDS_MeshElement* > tmp0Delems;
+  for ( size_t i = 0; i < groups.size(); ++i )
+  {
+    SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
+    for ( size_t iN = 0; iN < nodes.size(); ++iN )
+    {
+      SMDS_ElemIteratorPtr it0D = nodes[iN]->GetInverseElementIterator(SMDSAbs_0DElement);
+      if ( it0D->more() )
+        tmp0Delems.push_back( it0D->next() );
+      else
+        tmp0Delems.push_back( getMeshDS()->Add0DElement( nodes[iN] ));
+    }
+  }
+
+  // cout << endl << "INIT" << endl;
+  // for ( size_t i = 0; i < tmp0Delems.size(); ++i )
+  // {
+  //   cout << i << " ";
+  //   if ( i % 3 == 0 ) cout << "^ ";
+  //   tmp0Delems[i]->GetNode(0)->Print( cout );
+  // }
+
+  SMESH_TRY;
+
+  ::SMESH_MeshEditor::Sew_Error res, ok = ::SMESH_MeshEditor::SEW_OK;
+  int i0D = 0;
+  for ( size_t i = 0; i < groups.size(); ++i )
+  {
+    bool isBordToBord = true;
+    bool   groupSewed = false;
+    SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
+    for ( size_t iN = 3; iN+2 < nodes.size(); iN += 3 )
+    {
+      const SMDS_MeshNode* n0 = tmp0Delems[ i0D + 0 ]->GetNode( 0 );
+      const SMDS_MeshNode* n1 = tmp0Delems[ i0D + 1 ]->GetNode( 0 );
+      const SMDS_MeshNode* n2 = tmp0Delems[ i0D + 2 ]->GetNode( 0 );
+
+      const SMDS_MeshNode* n3 = tmp0Delems[ i0D + 0 + iN ]->GetNode( 0 );
+      const SMDS_MeshNode* n4 = tmp0Delems[ i0D + 1 + iN ]->GetNode( 0 );
+      const SMDS_MeshNode* n5 = tmp0Delems[ i0D + 2 + iN ]->GetNode( 0 );
+
+      if ( !n0 || !n1 || !n2 || !n3 || !n4 || !n5 )
+        continue;
+
+      // TIDSortedElemSet emptySet, avoidSet;
+      // if ( !SMESH_MeshAlgos::FindFaceInSet( n0, n1, emptySet, avoidSet))
+      // {
+      //   cout << "WRONG 2nd 1" << endl;
+      //   n0->Print( cout );
+      //   n1->Print( cout );
+      // }
+      // if ( !SMESH_MeshAlgos::FindFaceInSet( n3, n4, emptySet, avoidSet))
+      // {
+      //   cout << "WRONG 2nd 2" << endl;
+      //   n3->Print( cout );
+      //   n4->Print( cout );
+      // }
+
+      if ( !isBordToBord )
+      {
+        n1 = n2; // at border-to-side sewing only last side node (n1) is needed
+        n2 = 0;  //  and n2 is not used
+      }
+      // 1st border moves to 2nd
+      res = getEditor().SewFreeBorder( n3, n4, n5 ,// 1st
+                                       n0 ,n1 ,n2 ,// 2nd
+                                       /*2ndIsFreeBorder=*/ isBordToBord,
+                                       createPolygons, createPolyhedra);
+      groupSewed = ( res == ok );
+
+      isBordToBord = false;
+      // cout << endl << "SEWED GROUP " << i << " PART " << iN / 3 << endl;
+      // for ( size_t t = 0; t < tmp0Delems.size(); ++t )
+      // {
+      //   cout << t << " ";
+      //   if ( t % 3 == 0 ) cout << "^ ";
+      //   tmp0Delems[t]->GetNode(0)->Print( cout );
+      // }
+    }
+    i0D += nodes.size();
+    nbSewed += groupSewed;
+  }
 
 
-#define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
+  TPythonDump() << "nbSewed = " << this << ".SewCoincidentFreeBorders( "
+                << freeBorders     << ", "
+                << createPolygons  << ", "
+                << createPolyhedra << " )";
 
 
-static SMESH::SMESH_MeshEditor::Sew_Error convError( const::SMESH_MeshEditor::Sew_Error e )
-{
-  switch ( e ) {
-    RETCASE( SEW_OK );
-    RETCASE( SEW_BORDER1_NOT_FOUND );
-    RETCASE( SEW_BORDER2_NOT_FOUND );
-    RETCASE( SEW_BOTH_BORDERS_NOT_FOUND );
-    RETCASE( SEW_BAD_SIDE_NODES );
-    RETCASE( SEW_VOLUMES_TO_SPLIT );
-    RETCASE( SEW_DIFF_NB_OF_ELEMENTS );
-    RETCASE( SEW_TOPO_DIFF_SETS_OF_ELEMENTS );
-    RETCASE( SEW_BAD_SIDE1_NODES );
-    RETCASE( SEW_BAD_SIDE2_NODES );
+  SMESH_CATCH( SMESH::doNothing );
+
+  declareMeshModified( /*isReComputeSafe=*/false );
+
+  // remove tmp 0D elements
+  SMESH_TRY;
+  set< const SMDS_MeshElement* > removed0D;
+  for ( size_t i = 0; i < tmp0Delems.size(); ++i )
+  {
+    if ( removed0D.insert( tmp0Delems[i] ).second )
+      getMeshDS()->RemoveFreeElement( tmp0Delems[i], /*sm=*/0, /*fromGroups=*/false );
   }
   }
-  return SMESH::SMESH_MeshEditor::SEW_OK;
+  SMESH_CATCH( SMESH::throwCorbaException );
+
+  return nbSewed;
 }
 
 //=======================================================================
 }
 
 //=======================================================================
@@ -4918,7 +5369,9 @@ SMESH_MeshEditor_i::SewFreeBorders(CORBA::Long FirstNodeID1,
                                    CORBA::Long LastNodeID2,
                                    CORBA::Boolean CreatePolygons,
                                    CORBA::Boolean CreatePolyedrs)
                                    CORBA::Long LastNodeID2,
                                    CORBA::Boolean CreatePolygons,
                                    CORBA::Boolean CreatePolyedrs)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   SMESHDS_Mesh* aMesh = getMeshDS();
   initData();
 
   SMESHDS_Mesh* aMesh = getMeshDS();
@@ -4951,20 +5404,21 @@ SMESH_MeshEditor_i::SewFreeBorders(CORBA::Long FirstNodeID1,
 
   SMESH::SMESH_MeshEditor::Sew_Error error =
     convError( getEditor().SewFreeBorder (aBorderFirstNode,
 
   SMESH::SMESH_MeshEditor::Sew_Error error =
     convError( getEditor().SewFreeBorder (aBorderFirstNode,
-                                       aBorderSecondNode,
-                                       aBorderLastNode,
-                                       aSide2FirstNode,
-                                       aSide2SecondNode,
-                                       aSide2ThirdNode,
-                                       true,
-                                       CreatePolygons,
-                                       CreatePolyedrs) );
+                                          aBorderSecondNode,
+                                          aBorderLastNode,
+                                          aSide2FirstNode,
+                                          aSide2SecondNode,
+                                          aSide2ThirdNode,
+                                          true,
+                                          CreatePolygons,
+                                          CreatePolyedrs) );
 
 
 
 
-  myMesh->GetMeshDS()->Modified();
-  myMesh->SetIsModified( true );
-
+  declareMeshModified( /*isReComputeSafe=*/false );
   return error;
   return error;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return SMESH::SMESH_MeshEditor::Sew_Error(0);
 }
 
 
 }
 
 
@@ -4979,7 +5433,9 @@ SMESH_MeshEditor_i::SewConformFreeBorders(CORBA::Long FirstNodeID1,
                                           CORBA::Long LastNodeID1,
                                           CORBA::Long FirstNodeID2,
                                           CORBA::Long SecondNodeID2)
                                           CORBA::Long LastNodeID1,
                                           CORBA::Long FirstNodeID2,
                                           CORBA::Long SecondNodeID2)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   SMESHDS_Mesh* aMesh = getMeshDS();
   initData();
 
   SMESHDS_Mesh* aMesh = getMeshDS();
@@ -5008,19 +5464,19 @@ SMESH_MeshEditor_i::SewConformFreeBorders(CORBA::Long FirstNodeID1,
 
   SMESH::SMESH_MeshEditor::Sew_Error error =
     convError( getEditor().SewFreeBorder (aBorderFirstNode,
 
   SMESH::SMESH_MeshEditor::Sew_Error error =
     convError( getEditor().SewFreeBorder (aBorderFirstNode,
-                                       aBorderSecondNode,
-                                       aBorderLastNode,
-                                       aSide2FirstNode,
-                                       aSide2SecondNode,
-                                       aSide2ThirdNode,
-                                       true,
-                                       false, false) );
-
-
-  myMesh->GetMeshDS()->Modified();
-  myMesh->SetIsModified( true );
-
+                                          aBorderSecondNode,
+                                          aBorderLastNode,
+                                          aSide2FirstNode,
+                                          aSide2SecondNode,
+                                          aSide2ThirdNode,
+                                          true,
+                                          false, false) );
+
+  declareMeshModified( /*isReComputeSafe=*/false );
   return error;
   return error;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return SMESH::SMESH_MeshEditor::Sew_Error(0);
 }
 
 
 }
 
 
@@ -5037,7 +5493,9 @@ SMESH_MeshEditor_i::SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder,
                                     CORBA::Long LastNodeIDOnSide,
                                     CORBA::Boolean CreatePolygons,
                                     CORBA::Boolean CreatePolyedrs)
                                     CORBA::Long LastNodeIDOnSide,
                                     CORBA::Boolean CreatePolygons,
                                     CORBA::Boolean CreatePolyedrs)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   SMESHDS_Mesh* aMesh = getMeshDS();
   initData();
 
   SMESHDS_Mesh* aMesh = getMeshDS();
@@ -5068,20 +5526,20 @@ SMESH_MeshEditor_i::SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder,
 
   SMESH::SMESH_MeshEditor::Sew_Error error =
     convError( getEditor().SewFreeBorder (aBorderFirstNode,
 
   SMESH::SMESH_MeshEditor::Sew_Error error =
     convError( getEditor().SewFreeBorder (aBorderFirstNode,
-                                       aBorderSecondNode,
-                                       aBorderLastNode,
-                                       aSide2FirstNode,
-                                       aSide2SecondNode,
-                                       aSide2ThirdNode,
-                                       false,
-                                       CreatePolygons,
-                                       CreatePolyedrs) );
-
-
-  myMesh->GetMeshDS()->Modified();
-  myMesh->SetIsModified( true );
-
+                                          aBorderSecondNode,
+                                          aBorderLastNode,
+                                          aSide2FirstNode,
+                                          aSide2SecondNode,
+                                          aSide2ThirdNode,
+                                          false,
+                                          CreatePolygons,
+                                          CreatePolyedrs) );
+
+  declareMeshModified( /*isReComputeSafe=*/false );
   return error;
   return error;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return SMESH::SMESH_MeshEditor::Sew_Error(0);
 }
 
 
 }
 
 
@@ -5097,7 +5555,9 @@ SMESH_MeshEditor_i::SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
                                     CORBA::Long NodeID1OfSide2ToMerge,
                                     CORBA::Long NodeID2OfSide1ToMerge,
                                     CORBA::Long NodeID2OfSide2ToMerge)
                                     CORBA::Long NodeID1OfSide2ToMerge,
                                     CORBA::Long NodeID2OfSide1ToMerge,
                                     CORBA::Long NodeID2OfSide2ToMerge)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   SMESHDS_Mesh* aMesh = getMeshDS();
   initData();
 
   SMESHDS_Mesh* aMesh = getMeshDS();
@@ -5133,11 +5593,11 @@ SMESH_MeshEditor_i::SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
                                          aSecondNode1ToMerge,
                                          aSecondNode2ToMerge));
 
                                          aSecondNode1ToMerge,
                                          aSecondNode2ToMerge));
 
-
-  myMesh->GetMeshDS()->Modified();
-  myMesh->SetIsModified( true );
-
+  declareMeshModified( /*isReComputeSafe=*/false );
   return error;
   return error;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return SMESH::SMESH_MeshEditor::Sew_Error(0);
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -5151,7 +5611,9 @@ SMESH_MeshEditor_i::SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
 
 CORBA::Boolean SMESH_MeshEditor_i::ChangeElemNodes(CORBA::Long ide,
                                                    const SMESH::long_array& newIDs)
 
 CORBA::Boolean SMESH_MeshEditor_i::ChangeElemNodes(CORBA::Long ide,
                                                    const SMESH::long_array& newIDs)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   const SMDS_MeshElement* elem = getMeshDS()->FindElement(ide);
   initData();
 
   const SMDS_MeshElement* elem = getMeshDS()->FindElement(ide);
@@ -5171,27 +5633,49 @@ CORBA::Boolean SMESH_MeshEditor_i::ChangeElemNodes(CORBA::Long ide,
   TPythonDump() << "isDone = " << this << ".ChangeElemNodes( "
                 << ide << ", " << newIDs << " )";
 
   TPythonDump() << "isDone = " << this << ".ChangeElemNodes( "
                 << ide << ", " << newIDs << " )";
 
-  MESSAGE("ChangeElementNodes");
   bool res = getMeshDS()->ChangeElementNodes( elem, & aNodes[0], nbn1+1 );
 
   bool res = getMeshDS()->ChangeElementNodes( elem, & aNodes[0], nbn1+1 );
 
-  myMesh->GetMeshDS()->Modified();
-  if ( res )
-    myMesh->SetIsModified( true );
+  declareMeshModified( /*isReComputeSafe=*/ !res );
 
   return res;
 
   return res;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : ConvertToQuadratic
-//purpose  :
+/*!
+ * \brief Makes a part of the mesh quadratic or bi-quadratic
+ */
 //=======================================================================
 
 //=======================================================================
 
-void SMESH_MeshEditor_i::ConvertToQuadratic(CORBA::Boolean theForce3d)
+void SMESH_MeshEditor_i::convertToQuadratic(CORBA::Boolean            theForce3d,
+                                            CORBA::Boolean            theToBiQuad,
+                                            SMESH::SMESH_IDSource_ptr theObject)
+  throw (SALOME::SALOME_Exception)
 {
 {
-  getEditor().ConvertToQuadratic(theForce3d);
-  TPythonDump() << this << ".ConvertToQuadratic( " << theForce3d << " )";
-  myMesh->GetMeshDS()->Modified();
-  myMesh->SetIsModified( true );
+  SMESH_TRY;
+  initData();
+
+  TIDSortedElemSet elems;
+  bool elemsOK;
+  if ( !( elemsOK = CORBA::is_nil( theObject )))
+  {
+    elemsOK = idSourceToSet( theObject, getMeshDS(), elems,
+                             SMDSAbs_All, /*emptyIfIsMesh=*/true );
+  }
+  if ( elemsOK )
+  {
+    if ( !elems.empty() && (*elems.begin())->GetType() == SMDSAbs_Node )
+      THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
+
+    if ( elems.empty() ) getEditor().ConvertToQuadratic(theForce3d, theToBiQuad);
+    else                 getEditor().ConvertToQuadratic(theForce3d, elems, theToBiQuad);
+
+    declareMeshModified( /*isReComputeSafe=*/false );
+  }
+
+  SMESH_CATCH( SMESH::throwCorbaException );
 }
 
 //=======================================================================
 }
 
 //=======================================================================
@@ -5200,14 +5684,32 @@ void SMESH_MeshEditor_i::ConvertToQuadratic(CORBA::Boolean theForce3d)
 //=======================================================================
 
 CORBA::Boolean SMESH_MeshEditor_i::ConvertFromQuadratic()
 //=======================================================================
 
 CORBA::Boolean SMESH_MeshEditor_i::ConvertFromQuadratic()
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
+  initData();
+
   CORBA::Boolean isDone = getEditor().ConvertFromQuadratic();
   TPythonDump() << this << ".ConvertFromQuadratic()";
   CORBA::Boolean isDone = getEditor().ConvertFromQuadratic();
   TPythonDump() << this << ".ConvertFromQuadratic()";
-  myMesh->GetMeshDS()->Modified();
-  if ( isDone )
-    myMesh->SetIsModified( true );
+  declareMeshModified( /*isReComputeSafe=*/!isDone );
   return isDone;
   return isDone;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return false;
+}
+
+//=======================================================================
+//function : ConvertToQuadratic
+//purpose  :
+//=======================================================================
+
+void SMESH_MeshEditor_i::ConvertToQuadratic(CORBA::Boolean theForce3d)
+  throw (SALOME::SALOME_Exception)
+{
+  convertToQuadratic( theForce3d, false );
+  TPythonDump() << this << ".ConvertToQuadratic("<<theForce3d<<")";
 }
 }
+
 //================================================================================
 /*!
  * \brief Makes a part of the mesh quadratic
 //================================================================================
 /*!
  * \brief Makes a part of the mesh quadratic
@@ -5218,28 +5720,22 @@ void SMESH_MeshEditor_i::ConvertToQuadraticObject(CORBA::Boolean            theF
                                                   SMESH::SMESH_IDSource_ptr theObject)
   throw (SALOME::SALOME_Exception)
 {
                                                   SMESH::SMESH_IDSource_ptr theObject)
   throw (SALOME::SALOME_Exception)
 {
-  Unexpect aCatch(SALOME_SalomeException);
-  TPythonDump pyDump;
-  TIDSortedElemSet elems;
-  if ( idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true ))
-  {
-    if ( elems.empty() )
-    {
-      ConvertToQuadratic( theForce3d );
-    }
-    else if ( (*elems.begin())->GetType() == SMDSAbs_Node )
-    {
-      THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
-    }
-    else
-    {
-      getEditor().ConvertToQuadratic(theForce3d, elems);
-    }
-  }
-  myMesh->GetMeshDS()->Modified();
-  myMesh->SetIsModified( true );
+  convertToQuadratic( theForce3d, false, theObject );
+  TPythonDump() << this << ".ConvertToQuadraticObject("<<theForce3d<<", "<<theObject<<")";
+}
 
 
-  pyDump << this << ".ConvertToQuadraticObject( "<<theForce3d<<", "<<theObject<<" )";
+//================================================================================
+/*!
+ * \brief Makes a part of the mesh bi-quadratic
+ */
+//================================================================================
+
+void SMESH_MeshEditor_i::ConvertToBiQuadratic(CORBA::Boolean            theForce3d,
+                                              SMESH::SMESH_IDSource_ptr theObject)
+  throw (SALOME::SALOME_Exception)
+{
+  convertToQuadratic( theForce3d, true, theObject );
+  TPythonDump() << this << ".ConvertToBiQuadratic("<<theForce3d<<", "<<theObject<<")";
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -5251,8 +5747,11 @@ void SMESH_MeshEditor_i::ConvertToQuadraticObject(CORBA::Boolean            theF
 void SMESH_MeshEditor_i::ConvertFromQuadraticObject(SMESH::SMESH_IDSource_ptr theObject)
   throw (SALOME::SALOME_Exception)
 {
 void SMESH_MeshEditor_i::ConvertFromQuadraticObject(SMESH::SMESH_IDSource_ptr theObject)
   throw (SALOME::SALOME_Exception)
 {
-  Unexpect aCatch(SALOME_SalomeException);
+  SMESH_TRY;
+  initData();
+
   TPythonDump pyDump;
   TPythonDump pyDump;
+
   TIDSortedElemSet elems;
   if ( idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true ))
   {
   TIDSortedElemSet elems;
   if ( idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true ))
   {
@@ -5269,10 +5768,11 @@ void SMESH_MeshEditor_i::ConvertFromQuadraticObject(SMESH::SMESH_IDSource_ptr th
       getEditor().ConvertFromQuadratic(elems);
     }
   }
       getEditor().ConvertFromQuadratic(elems);
     }
   }
-  myMesh->GetMeshDS()->Modified();
-  myMesh->SetIsModified( true );
+  declareMeshModified( /*isReComputeSafe=*/false );
 
   pyDump << this << ".ConvertFromQuadraticObject( "<<theObject<<" )";
 
   pyDump << this << ".ConvertFromQuadraticObject( "<<theObject<<" )";
+
+  SMESH_CATCH( SMESH::throwCorbaException );
 }
 
 //=======================================================================
 }
 
 //=======================================================================
@@ -5284,8 +5784,7 @@ SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::makeMesh(const char* theMeshName)
 {
   SMESH_Gen_i*              gen = SMESH_Gen_i::GetSMESHGen();
   SMESH::SMESH_Mesh_var    mesh = gen->CreateEmptyMesh();
 {
   SMESH_Gen_i*              gen = SMESH_Gen_i::GetSMESHGen();
   SMESH::SMESH_Mesh_var    mesh = gen->CreateEmptyMesh();
-  SALOMEDS::Study_var     study = gen->GetCurrentStudy();
-  SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject( study, mesh );
+  SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject( mesh );
   gen->SetName( meshSO, theMeshName, "Mesh" );
   gen->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED");
 
   gen->SetName( meshSO, theMeshName, "Mesh" );
   gen->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED");
 
@@ -5293,16 +5792,16 @@ SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::makeMesh(const char* theMeshName)
 }
 
 //=======================================================================
 }
 
 //=======================================================================
-//function : DumpGroupsList
+//function : dumpGroupsList
 //purpose  :
 //=======================================================================
 //purpose  :
 //=======================================================================
-void SMESH_MeshEditor_i::DumpGroupsList(TPythonDump &               theDumpPython,
+
+void SMESH_MeshEditor_i::dumpGroupsList(TPythonDump &               theDumpPython,
                                         const SMESH::ListOfGroups * theGroupList)
 {
                                         const SMESH::ListOfGroups * theGroupList)
 {
-  bool isDumpGroupList = theGroupList && theGroupList->length() > 0;
-  if(isDumpGroupList) {
+  bool isDumpGroupList = ( theGroupList && theGroupList->length() > 0 );
+  if ( isDumpGroupList )
     theDumpPython << theGroupList << " = ";
     theDumpPython << theGroupList << " = ";
-  }
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -5312,10 +5811,11 @@ void SMESH_MeshEditor_i::DumpGroupsList(TPythonDump &               theDumpPytho
   \return unique name
 */
 //================================================================================
   \return unique name
 */
 //================================================================================
-string SMESH_MeshEditor_i::generateGroupName(const string& thePrefix)
+
+std::string SMESH_MeshEditor_i::GenerateGroupName(const std::string& thePrefix)
 {
   SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
 {
   SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
-  set<string> groupNames;
+  set<std::string> groupNames;
 
   // Get existing group names
   for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) {
 
   // Get existing group names
   for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) {
@@ -5328,15 +5828,171 @@ string SMESH_MeshEditor_i::generateGroupName(const string& thePrefix)
   }
 
   // Find new name
   }
 
   // Find new name
-  string name = thePrefix;
+  std::string name = thePrefix;
   int index = 0;
 
   while (!groupNames.insert(name).second)
   int index = 0;
 
   while (!groupNames.insert(name).second)
-    name = SMESH_Comment( thePrefix ) << "_" << index;
+    name = SMESH_Comment( thePrefix ) << "_" << index++;
 
   return name;
 }
 
 
   return name;
 }
 
+//================================================================================
+/*!
+ * \brief Prepare SMESH_IDSource for work
+ */
+//================================================================================
+
+void SMESH_MeshEditor_i::prepareIdSource(SMESH::SMESH_IDSource_ptr theObject)
+{
+  if ( SMESH::Filter_i* filter = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
+  {
+    SMESH::SMESH_Mesh_var mesh = myMesh_i->_this();
+    filter->SetMesh( mesh );
+  }
+}
+//================================================================================
+/*!
+ * \brief Retrieve elements of given type from SMESH_IDSource
+ */
+//================================================================================
+
+bool SMESH_MeshEditor_i::idSourceToSet(SMESH::SMESH_IDSource_ptr  theIDSource,
+                                       const SMESHDS_Mesh*        theMeshDS,
+                                       TIDSortedElemSet&          theElemSet,
+                                       const SMDSAbs_ElementType  theType,
+                                       const bool                 emptyIfIsMesh,
+                                       IDSource_Error*            error)
+
+{
+  if ( error ) *error = IDSource_OK;
+
+  if ( CORBA::is_nil( theIDSource ))
+  {
+    if ( error ) *error = IDSource_INVALID;
+    return false;
+  }
+  if ( emptyIfIsMesh && SMESH::DownCast<SMESH_Mesh_i*>( theIDSource ))
+  {
+    if ( error && theMeshDS->GetMeshInfo().NbElements( theType ) == 0 )
+      *error = IDSource_EMPTY;
+    return true;
+  }
+  if ( getMeshDS() == theMeshDS ) // check if theIDSource belongs to myMesh
+  {
+    SMESH::SMESH_Mesh_var mesh = theIDSource->GetMesh();
+    SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
+    if ( mesh_i && mesh_i != myMesh_i )
+    {
+      if ( error )
+        *error = IDSource_INVALID;
+      return false;
+    }
+  }
+  prepareIdSource( theIDSource );
+  SMESH::long_array_var anIDs = theIDSource->GetIDs();
+  if ( anIDs->length() == 0 )
+  {
+    if ( error ) *error = IDSource_EMPTY;
+    return false;
+  }
+  SMESH::array_of_ElementType_var types = theIDSource->GetTypes();
+  if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
+  {
+    if ( theType == SMDSAbs_All || theType == SMDSAbs_Node )
+    {
+      arrayToSet( anIDs, getMeshDS(), theElemSet, SMDSAbs_Node );
+    }
+    else
+    {
+      if ( error ) *error = IDSource_INVALID;
+      return false;
+    }
+  }
+  else
+  {
+    arrayToSet( anIDs, getMeshDS(), theElemSet, theType);
+    if ( bool(anIDs->length()) != bool(theElemSet.size()))
+    {
+      if ( error ) *error = IDSource_INVALID;
+      return false;
+    }
+  }
+  return true;
+}
+
+//================================================================================
+/*!
+ * \brief Duplicates given elements, i.e. creates new elements based on the
+ *        same nodes as the given ones.
+ * \param theElements - container of elements to duplicate.
+ * \param theGroupName - a name of group to contain the generated elements.
+ *                    If a group with such a name already exists, the new elements
+ *                    are added to the existing group, else a new group is created.
+ *                    If \a theGroupName is empty, new elements are not added 
+ *                    in any group.
+ * \return a group where the new elements are added. NULL if theGroupName == "".
+ * \sa DoubleNode()
+ */
+//================================================================================
+
+SMESH::SMESH_Group_ptr
+SMESH_MeshEditor_i::DoubleElements(SMESH::SMESH_IDSource_ptr theElements,
+                                   const char*               theGroupName)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH::SMESH_Group_var newGroup;
+
+  SMESH_TRY;
+  initData();
+
+  TPythonDump pyDump;
+
+  TIDSortedElemSet elems;
+  if ( idSourceToSet( theElements, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true))
+  {
+    getEditor().DoubleElements( elems );
+
+    if ( strlen( theGroupName ) && !getEditor().GetLastCreatedElems().empty() )
+    {
+      // group type
+      SMESH::ElementType type =
+        SMESH::ElementType( getEditor().GetLastCreatedElems()[0]->GetType() );
+      // find existing group
+      SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
+      for ( size_t i = 0; i < groups->length(); ++i )
+        if ( groups[i]->GetType() == type )
+        {
+          CORBA::String_var name = groups[i]->GetName();
+          if ( strcmp( name, theGroupName ) == 0 ) {
+            newGroup = SMESH::SMESH_Group::_narrow( groups[i] );
+            break;
+          }
+        }
+      // create a new group
+      if ( newGroup->_is_nil() )
+        newGroup = myMesh_i->CreateGroup( type, theGroupName );
+      // fill newGroup
+      if ( SMESH_Group_i* group_i = SMESH::DownCast< SMESH_Group_i* >( newGroup ))
+      {
+        SMESHDS_Group* groupDS = static_cast< SMESHDS_Group* >( group_i->GetGroupDS() );
+        const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
+        for ( size_t i = 0; i < aSeq.size(); i++ )
+          groupDS->SMDSGroup().Add( aSeq[i] );
+      }
+    }
+  }
+  // python dump
+  if ( !newGroup->_is_nil() )
+    pyDump << newGroup << " = ";
+  pyDump << this << ".DoubleElements( "
+         << theElements << ", " << "'" << theGroupName <<"')";
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+
+  return newGroup._retn();
+}
+
 //================================================================================
 /*!
   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
 //================================================================================
 /*!
   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
@@ -5351,7 +6007,9 @@ string SMESH_MeshEditor_i::generateGroupName(const string& thePrefix)
 
 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodes( const SMESH::long_array& theNodes,
                                                 const SMESH::long_array& theModifiedElems )
 
 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodes( const SMESH::long_array& theNodes,
                                                 const SMESH::long_array& theModifiedElems )
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   list< int > aListOfNodes;
   initData();
 
   list< int > aListOfNodes;
@@ -5365,14 +6023,15 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodes( const SMESH::long_array& theNode
 
   bool aResult = getEditor().DoubleNodes( aListOfNodes, aListOfElems );
 
 
   bool aResult = getEditor().DoubleNodes( aListOfNodes, aListOfElems );
 
-  myMesh->GetMeshDS()->Modified();
-  if ( aResult )
-    myMesh->SetIsModified( true );
+  declareMeshModified( /*isReComputeSafe=*/ !aResult );
 
   // Update Python script
   TPythonDump() << this << ".DoubleNodes( " << theNodes << ", "<< theModifiedElems << " )";
 
   return aResult;
 
   // Update Python script
   TPythonDump() << this << ".DoubleNodes( " << theNodes << ", "<< theModifiedElems << " )";
 
   return aResult;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -5388,7 +6047,9 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodes( const SMESH::long_array& theNode
 
 CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long              theNodeId,
                                                const SMESH::long_array& theModifiedElems )
 
 CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long              theNodeId,
                                                const SMESH::long_array& theModifiedElems )
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   SMESH::long_array_var aNodes = new SMESH::long_array;
   aNodes->length( 1 );
   aNodes[ 0 ] = theNodeId;
   SMESH::long_array_var aNodes = new SMESH::long_array;
   aNodes->length( 1 );
   aNodes[ 0 ] = theNodeId;
@@ -5400,6 +6061,9 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long              theNodeI
   pyDump << this << ".DoubleNode( " << theNodeId << ", " << theModifiedElems << " )";
 
   return done;
   pyDump << this << ".DoubleNode( " << theNodeId << ", " << theModifiedElems << " )";
 
   return done;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -5415,7 +6079,9 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long              theNodeI
 
 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup(SMESH::SMESH_GroupBase_ptr theNodes,
                                                    SMESH::SMESH_GroupBase_ptr theModifiedElems )
 
 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup(SMESH::SMESH_GroupBase_ptr theNodes,
                                                    SMESH::SMESH_GroupBase_ptr theModifiedElems )
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
     return false;
 
   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
     return false;
 
@@ -5424,10 +6090,7 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup(SMESH::SMESH_GroupBase_ptr th
   if ( !CORBA::is_nil( theModifiedElems ) )
     aModifiedElems = theModifiedElems->GetListOfID();
   else
   if ( !CORBA::is_nil( theModifiedElems ) )
     aModifiedElems = theModifiedElems->GetListOfID();
   else
-  {
     aModifiedElems = new SMESH::long_array;
     aModifiedElems = new SMESH::long_array;
-    aModifiedElems->length( 0 );
-  }
 
   TPythonDump pyDump; // suppress dump by the next line
 
 
   TPythonDump pyDump; // suppress dump by the next line
 
@@ -5436,8 +6099,12 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup(SMESH::SMESH_GroupBase_ptr th
   pyDump << this << ".DoubleNodeGroup( " << theNodes << ", " << theModifiedElems << " )";
 
   return done;
   pyDump << this << ".DoubleNodeGroup( " << theNodes << ", " << theModifiedElems << " )";
 
   return done;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 }
 
+//================================================================================
 /*!
  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
  * Works as DoubleNodeGroup(), but returns a new group with newly created nodes.
 /*!
  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
  * Works as DoubleNodeGroup(), but returns a new group with newly created nodes.
@@ -5446,10 +6113,14 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup(SMESH::SMESH_GroupBase_ptr th
  * \return a new group with newly created nodes
  * \sa DoubleNodeGroup()
  */
  * \return a new group with newly created nodes
  * \sa DoubleNodeGroup()
  */
+//================================================================================
+
 SMESH::SMESH_Group_ptr
 SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
                                         SMESH::SMESH_GroupBase_ptr theModifiedElems )
 SMESH::SMESH_Group_ptr
 SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
                                         SMESH::SMESH_GroupBase_ptr theModifiedElems )
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   SMESH::SMESH_Group_var aNewGroup;
 
   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
   SMESH::SMESH_Group_var aNewGroup;
 
   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
@@ -5473,8 +6144,8 @@ SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
     // Create group with newly created nodes
     SMESH::long_array_var anIds = GetLastCreatedNodes();
     if (anIds->length() > 0) {
     // Create group with newly created nodes
     SMESH::long_array_var anIds = GetLastCreatedNodes();
     if (anIds->length() > 0) {
-      string anUnindexedName (theNodes->GetName());
-      string aNewName = generateGroupName(anUnindexedName + "_double");
+      std::string anUnindexedName (theNodes->GetName());
+      std::string aNewName = GenerateGroupName(anUnindexedName + "_double");
       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
       aNewGroup->Add(anIds);
       pyDump << aNewGroup << " = ";
       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
       aNewGroup->Add(anIds);
       pyDump << aNewGroup << " = ";
@@ -5485,6 +6156,9 @@ SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
          << theModifiedElems << " )";
 
   return aNewGroup._retn();
          << theModifiedElems << " )";
 
   return aNewGroup._retn();
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -5500,10 +6174,11 @@ SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
 
 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& theNodes,
                                                     const SMESH::ListOfGroups& theModifiedElems )
 
 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& theNodes,
                                                     const SMESH::ListOfGroups& theModifiedElems )
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   initData();
 
-
   std::list< int > aNodes;
   int i, n, j, m;
   for ( i = 0, n = theNodes.length(); i < n; i++ )
   std::list< int > aNodes;
   int i, n, j, m;
   for ( i = 0, n = theNodes.length(); i < n; i++ )
@@ -5531,15 +6206,14 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& t
 
   bool aResult = getEditor().DoubleNodes( aNodes, anElems );
 
 
   bool aResult = getEditor().DoubleNodes( aNodes, anElems );
 
-
-  myMesh->GetMeshDS()->Modified();
-  if ( aResult )
-    myMesh->SetIsModified( true );
-
+  declareMeshModified( /*isReComputeSafe=*/false );
 
   TPythonDump() << this << ".DoubleNodeGroups( " << theNodes << ", " << theModifiedElems << " )";
 
   return aResult;
 
   TPythonDump() << this << ".DoubleNodeGroups( " << theNodes << ", " << theModifiedElems << " )";
 
   return aResult;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -5556,6 +6230,7 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& t
 SMESH::SMESH_Group_ptr
 SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
                                          const SMESH::ListOfGroups& theModifiedElems )
 SMESH::SMESH_Group_ptr
 SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
                                          const SMESH::ListOfGroups& theModifiedElems )
+  throw (SALOME::SALOME_Exception)
 {
   SMESH::SMESH_Group_var aNewGroup;
 
 {
   SMESH::SMESH_Group_var aNewGroup;
 
@@ -5568,8 +6243,8 @@ SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
     // Create group with newly created nodes
     SMESH::long_array_var anIds = GetLastCreatedNodes();
     if (anIds->length() > 0) {
     // Create group with newly created nodes
     SMESH::long_array_var anIds = GetLastCreatedNodes();
     if (anIds->length() > 0) {
-      string anUnindexedName (theNodes[0]->GetName());
-      string aNewName = generateGroupName(anUnindexedName + "_double");
+      std::string anUnindexedName (theNodes[0]->GetName());
+      std::string aNewName = GenerateGroupName(anUnindexedName + "_double");
       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
       aNewGroup->Add(anIds);
       pyDump << aNewGroup << " = ";
       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
       aNewGroup->Add(anIds);
       pyDump << aNewGroup << " = ";
@@ -5599,11 +6274,11 @@ SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theElems,
                                                    const SMESH::long_array& theNodesNot,
                                                    const SMESH::long_array& theAffectedElems )
 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theElems,
                                                    const SMESH::long_array& theNodesNot,
                                                    const SMESH::long_array& theAffectedElems )
-
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   initData();
 
-
   SMESHDS_Mesh* aMeshDS = getMeshDS();
   TIDSortedElemSet anElems, aNodes, anAffected;
   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
   SMESHDS_Mesh* aMeshDS = getMeshDS();
   TIDSortedElemSet anElems, aNodes, anAffected;
   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
@@ -5612,15 +6287,15 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theE
 
   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
 
 
   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
 
-
-  myMesh->GetMeshDS()->Modified();
-  if ( aResult )
-    myMesh->SetIsModified( true );
-
   // Update Python script
   TPythonDump() << this << ".DoubleNodeElem( " << theElems << ", "
                 << theNodesNot << ", " << theAffectedElems << " )";
   // Update Python script
   TPythonDump() << this << ".DoubleNodeElem( " << theElems << ", "
                 << theNodesNot << ", " << theAffectedElems << " )";
+
+  declareMeshModified( /*isReComputeSafe=*/false );
   return aResult;
   return aResult;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -5640,8 +6315,9 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theE
 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion ( const SMESH::long_array& theElems,
                                                             const SMESH::long_array& theNodesNot,
                                                             GEOM::GEOM_Object_ptr    theShape )
 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion ( const SMESH::long_array& theElems,
                                                             const SMESH::long_array& theNodesNot,
                                                             GEOM::GEOM_Object_ptr    theShape )
-
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
 
   initData();
 
 
@@ -5653,15 +6329,15 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion ( const SMESH::long_ar
   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
 
   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
 
-
-  myMesh->GetMeshDS()->Modified();
-  if ( aResult )
-    myMesh->SetIsModified( true );
-
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodeElemInRegion( " << theElems << ", "
                 << theNodesNot << ", " << theShape << " )";
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodeElemInRegion( " << theElems << ", "
                 << theNodesNot << ", " << theShape << " )";
+
+  declareMeshModified( /*isReComputeSafe=*/false );
   return aResult;
   return aResult;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -5676,10 +6352,13 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion ( const SMESH::long_ar
 */
 //================================================================================
 
 */
 //================================================================================
 
-CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_ptr theElems,
-                                                       SMESH::SMESH_GroupBase_ptr theNodesNot,
-                                                       SMESH::SMESH_GroupBase_ptr theAffectedElems)
+CORBA::Boolean
+SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_ptr theElems,
+                                        SMESH::SMESH_GroupBase_ptr theNodesNot,
+                                        SMESH::SMESH_GroupBase_ptr theAffectedElems)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
     return false;
 
   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
     return false;
 
@@ -5694,17 +6373,18 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_pt
 
   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
 
 
   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
 
-
-  myMesh->GetMeshDS()->Modified();
-  if ( aResult )
-    myMesh->SetIsModified( true );
-
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroup( " << theElems << ", "
                 << theNodesNot << ", " << theAffectedElems << " )";
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroup( " << theElems << ", "
                 << theNodesNot << ", " << theAffectedElems << " )";
+
+  declareMeshModified( /*isReComputeSafe=*/false );
   return aResult;
   return aResult;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 }
 
+//================================================================================
 /*!
  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
 /*!
  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
@@ -5715,10 +6395,13 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_pt
  * \return a new group with newly created elements
  * \sa DoubleNodeElemGroup()
  */
  * \return a new group with newly created elements
  * \sa DoubleNodeElemGroup()
  */
+//================================================================================
+
 SMESH::SMESH_Group_ptr
 SMESH_MeshEditor_i::DoubleNodeElemGroupNew(SMESH::SMESH_GroupBase_ptr theElems,
                                            SMESH::SMESH_GroupBase_ptr theNodesNot,
                                            SMESH::SMESH_GroupBase_ptr theAffectedElems)
 SMESH::SMESH_Group_ptr
 SMESH_MeshEditor_i::DoubleNodeElemGroupNew(SMESH::SMESH_GroupBase_ptr theElems,
                                            SMESH::SMESH_GroupBase_ptr theNodesNot,
                                            SMESH::SMESH_GroupBase_ptr theAffectedElems)
+  throw (SALOME::SALOME_Exception)
 {
   TPythonDump pyDump;
   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroup2New( theElems,
 {
   TPythonDump pyDump;
   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroup2New( theElems,
@@ -5736,13 +6419,28 @@ SMESH_MeshEditor_i::DoubleNodeElemGroupNew(SMESH::SMESH_GroupBase_ptr theElems,
   return elemGroup._retn();
 }
 
   return elemGroup._retn();
 }
 
+//================================================================================
+/*!
+ * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
+ * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
+ * \param theElems - group of of elements (edges or faces) to be replicated
+ * \param theNodesNot - group of nodes not to replicated
+ * \param theAffectedElems - group of elements to which the replicated nodes
+ *        should be associated to.
+ * \return a new group with newly created elements
+ * \sa DoubleNodeElemGroup()
+ */
+//================================================================================
+
 SMESH::ListOfGroups*
 SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
                                             SMESH::SMESH_GroupBase_ptr theNodesNot,
                                             SMESH::SMESH_GroupBase_ptr theAffectedElems,
                                             CORBA::Boolean             theElemGroupNeeded,
                                             CORBA::Boolean             theNodeGroupNeeded)
 SMESH::ListOfGroups*
 SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
                                             SMESH::SMESH_GroupBase_ptr theNodesNot,
                                             SMESH::SMESH_GroupBase_ptr theAffectedElems,
                                             CORBA::Boolean             theElemGroupNeeded,
                                             CORBA::Boolean             theNodeGroupNeeded)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
   aTwoGroups->length( 2 );
   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
   aTwoGroups->length( 2 );
@@ -5762,25 +6460,23 @@ SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
 
   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
 
 
   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
 
-  myMesh->GetMeshDS()->Modified();
+  declareMeshModified( /*isReComputeSafe=*/ !aResult );
 
   TPythonDump pyDump;
 
   if ( aResult )
   {
 
   TPythonDump pyDump;
 
   if ( aResult )
   {
-    myMesh->SetIsModified( true );
-
     // Create group with newly created elements
     CORBA::String_var elemGroupName = theElems->GetName();
     // Create group with newly created elements
     CORBA::String_var elemGroupName = theElems->GetName();
-    string aNewName = generateGroupName( string(elemGroupName.in()) + "_double");
-    if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
+    std::string aNewName = GenerateGroupName( std::string(elemGroupName.in()) + "_double");
+    if ( !getEditor().GetLastCreatedElems().empty() && theElemGroupNeeded )
     {
       SMESH::long_array_var anIds = GetLastCreatedElems();
       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
       aNewElemGroup->Add(anIds);
     }
     {
       SMESH::long_array_var anIds = GetLastCreatedElems();
       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
       aNewElemGroup->Add(anIds);
     }
-    if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
+    if ( !getEditor().GetLastCreatedNodes().empty() && theNodeGroupNeeded )
     {
       SMESH::long_array_var anIds = GetLastCreatedNodes();
       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
     {
       SMESH::long_array_var anIds = GetLastCreatedNodes();
       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
@@ -5805,6 +6501,9 @@ SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
   aTwoGroups[0] = aNewElemGroup._retn();
   aTwoGroups[1] = aNewNodeGroup._retn();
   return aTwoGroups._retn();
   aTwoGroups[0] = aNewElemGroup._retn();
   aTwoGroups[1] = aNewNodeGroup._retn();
   return aTwoGroups._retn();
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -5820,11 +6519,13 @@ SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
 */
 //================================================================================
 
 */
 //================================================================================
 
-CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion(SMESH::SMESH_GroupBase_ptr theElems,
-                                                               SMESH::SMESH_GroupBase_ptr theNodesNot,
-                                                               GEOM::GEOM_Object_ptr      theShape )
-
+CORBA::Boolean
+SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion(SMESH::SMESH_GroupBase_ptr theElems,
+                                                SMESH::SMESH_GroupBase_ptr theNodesNot,
+                                                GEOM::GEOM_Object_ptr      theShape )
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
     return false;
 
   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
     return false;
 
@@ -5840,27 +6541,25 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion(SMESH::SMESH_Grou
   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
 
 
   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
 
 
-  myMesh->GetMeshDS()->Modified();
-  if ( aResult )
-    myMesh->SetIsModified( true );
+  declareMeshModified( /*isReComputeSafe=*/ !aResult );
 
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupInRegion( " << theElems << ", "
                 << theNodesNot << ", " << theShape << " )";
   return aResult;
 
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupInRegion( " << theElems << ", "
                 << theNodesNot << ", " << theShape << " )";
   return aResult;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //================================================================================
 /*!
 }
 
 //================================================================================
 /*!
-  \brief Creates a hole in a mesh by doubling the nodes of some particular elements
-  This method provided for convenience works as DoubleNodes() described above.
-  \param theElems - list of groups of elements (edges or faces) to be replicated
-  \param theNodesNot - list of groups of nodes not to replicated
-  \param theAffectedElems - group of elements to which the replicated nodes
-  should be associated to.
-  \return TRUE if operation has been completed successfully, FALSE otherwise
-  \sa DoubleNodeGroup(), DoubleNodes(), DoubleNodeElemGroupsNew()
-*/
+ * \brief Re-load elements from a list of groups into a TIDSortedElemSet
+ *  \param [in] theGrpList - groups
+ *  \param [in] theMeshDS -  mesh
+ *  \param [out] theElemSet - set of elements
+ *  \param [in] theIsNodeGrp - is \a theGrpList includes goups of nodes
+ */
 //================================================================================
 
 static void listOfGroupToSet(const SMESH::ListOfGroups& theGrpList,
 //================================================================================
 
 static void listOfGroupToSet(const SMESH::ListOfGroups& theGrpList,
@@ -5880,10 +6579,26 @@ static void listOfGroupToSet(const SMESH::ListOfGroups& theGrpList,
   }
 }
 
   }
 }
 
-CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroups(const SMESH::ListOfGroups& theElems,
-                                                        const SMESH::ListOfGroups& theNodesNot,
-                                                        const SMESH::ListOfGroups& theAffectedElems)
+//================================================================================
+/*!
+  \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
+  This method provided for convenience works as DoubleNodes() described above.
+  \param theElems - list of groups of elements (edges or faces) to be replicated
+  \param theNodesNot - list of groups of nodes not to replicated
+  \param theAffectedElems - group of elements to which the replicated nodes
+  should be associated to.
+  \return TRUE if operation has been completed successfully, FALSE otherwise
+  \sa DoubleNodeGroup(), DoubleNodes(), DoubleNodeElemGroupsNew()
+*/
+//================================================================================
+
+CORBA::Boolean
+SMESH_MeshEditor_i::DoubleNodeElemGroups(const SMESH::ListOfGroups& theElems,
+                                         const SMESH::ListOfGroups& theNodesNot,
+                                         const SMESH::ListOfGroups& theAffectedElems)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
 
   initData();
 
 
@@ -5895,15 +6610,15 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroups(const SMESH::ListOfGroup
 
   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
 
 
   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
 
-
-  myMesh->GetMeshDS()->Modified();
-  if ( aResult )
-    myMesh->SetIsModified( true );
-
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroups( " << &theElems << ", "
                 << &theNodesNot << ", " << &theAffectedElems << " )";
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroups( " << &theElems << ", "
                 << &theNodesNot << ", " << &theAffectedElems << " )";
+
+  declareMeshModified( /*isReComputeSafe=*/false );
   return aResult;
   return aResult;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -5923,6 +6638,7 @@ SMESH::SMESH_Group_ptr
 SMESH_MeshEditor_i::DoubleNodeElemGroupsNew(const SMESH::ListOfGroups& theElems,
                                             const SMESH::ListOfGroups& theNodesNot,
                                             const SMESH::ListOfGroups& theAffectedElems)
 SMESH_MeshEditor_i::DoubleNodeElemGroupsNew(const SMESH::ListOfGroups& theElems,
                                             const SMESH::ListOfGroups& theNodesNot,
                                             const SMESH::ListOfGroups& theAffectedElems)
+  throw (SALOME::SALOME_Exception)
 {
   TPythonDump pyDump;
   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroups2New( theElems,
 {
   TPythonDump pyDump;
   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroups2New( theElems,
@@ -5940,13 +6656,28 @@ SMESH_MeshEditor_i::DoubleNodeElemGroupsNew(const SMESH::ListOfGroups& theElems,
   return elemGroup._retn();
 }
 
   return elemGroup._retn();
 }
 
+//================================================================================
+/*!
+ * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
+ * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
+  \param theElems - list of groups of elements (edges or faces) to be replicated
+  \param theNodesNot - list of groups of nodes not to replicated
+  \param theAffectedElems - group of elements to which the replicated nodes
+  should be associated to.
+ * \return a new group with newly created elements
+ * \sa DoubleNodeElemGroups()
+ */
+//================================================================================
+
 SMESH::ListOfGroups*
 SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems,
                                              const SMESH::ListOfGroups& theNodesNot,
                                              const SMESH::ListOfGroups& theAffectedElems,
                                              CORBA::Boolean             theElemGroupNeeded,
                                              CORBA::Boolean             theNodeGroupNeeded)
 SMESH::ListOfGroups*
 SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems,
                                              const SMESH::ListOfGroups& theNodesNot,
                                              const SMESH::ListOfGroups& theAffectedElems,
                                              CORBA::Boolean             theElemGroupNeeded,
                                              CORBA::Boolean             theNodeGroupNeeded)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
   aTwoGroups->length( 2 );
   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
   aTwoGroups->length( 2 );
@@ -5962,24 +6693,22 @@ SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems
 
   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
 
 
   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
 
+  declareMeshModified( /*isReComputeSafe=*/ !aResult );
 
 
-  myMesh->GetMeshDS()->Modified();
   TPythonDump pyDump;
   if ( aResult )
   {
   TPythonDump pyDump;
   if ( aResult )
   {
-    myMesh->SetIsModified( true );
-
     // Create group with newly created elements
     CORBA::String_var elemGroupName = theElems[0]->GetName();
     // Create group with newly created elements
     CORBA::String_var elemGroupName = theElems[0]->GetName();
-    string aNewName = generateGroupName( string(elemGroupName.in()) + "_double");
-    if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
+    std::string aNewName = GenerateGroupName( std::string(elemGroupName.in()) + "_double");
+    if ( !getEditor().GetLastCreatedElems().empty() && theElemGroupNeeded )
     {
       SMESH::long_array_var anIds = GetLastCreatedElems();
       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
       aNewElemGroup->Add(anIds);
     }
     {
       SMESH::long_array_var anIds = GetLastCreatedElems();
       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
       aNewElemGroup->Add(anIds);
     }
-    if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
+    if ( !getEditor().GetLastCreatedNodes().empty() && theNodeGroupNeeded )
     {
       SMESH::long_array_var anIds = GetLastCreatedNodes();
       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
     {
       SMESH::long_array_var anIds = GetLastCreatedNodes();
       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
@@ -6004,6 +6733,9 @@ SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems
   aTwoGroups[0] = aNewElemGroup._retn();
   aTwoGroups[1] = aNewNodeGroup._retn();
   return aTwoGroups._retn();
   aTwoGroups[0] = aNewElemGroup._retn();
   aTwoGroups[1] = aNewNodeGroup._retn();
   return aTwoGroups._retn();
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -6024,7 +6756,9 @@ CORBA::Boolean
 SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theElems,
                                                  const SMESH::ListOfGroups& theNodesNot,
                                                  GEOM::GEOM_Object_ptr      theShape )
 SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theElems,
                                                  const SMESH::ListOfGroups& theNodesNot,
                                                  GEOM::GEOM_Object_ptr      theShape )
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
 
   initData();
 
 
@@ -6036,20 +6770,21 @@ SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theE
   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
 
   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
 
-
-  myMesh->GetMeshDS()->Modified();
-  if ( aResult )
-    myMesh->SetIsModified( true );
-
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupsInRegion( " << &theElems << ", "
                 << &theNodesNot << ", " << theShape << " )";
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupsInRegion( " << &theElems << ", "
                 << &theNodesNot << ", " << theShape << " )";
+
+  declareMeshModified( /*isReComputeSafe=*/ !aResult );
   return aResult;
   return aResult;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //================================================================================
 /*!
 }
 
 //================================================================================
 /*!
-  \brief Identify the elements that will be affected by node duplication (actual duplication is not performed.
+  \brief Identify the elements that will be affected by node duplication (actual
+         duplication is not performed.
   This method is the first step of DoubleNodeElemGroupsInRegion.
   \param theElems - list of groups of elements (edges or faces) to be replicated
   \param theNodesNot - list of groups of nodes not to replicated
   This method is the first step of DoubleNodeElemGroupsInRegion.
   \param theElems - list of groups of elements (edges or faces) to be replicated
   \param theNodesNot - list of groups of nodes not to replicated
@@ -6058,21 +6793,19 @@ SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theE
          The replicated nodes should be associated to affected elements.
   \return groups of affected elements
   \sa DoubleNodeElemGroupsInRegion()
          The replicated nodes should be associated to affected elements.
   \return groups of affected elements
   \sa DoubleNodeElemGroupsInRegion()
- */
+*/
 //================================================================================
 SMESH::ListOfGroups*
 SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theElems,
                                                 const SMESH::ListOfGroups& theNodesNot,
                                                 GEOM::GEOM_Object_ptr      theShape )
 //================================================================================
 SMESH::ListOfGroups*
 SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theElems,
                                                 const SMESH::ListOfGroups& theNodesNot,
                                                 GEOM::GEOM_Object_ptr      theShape )
+  throw (SALOME::SALOME_Exception)
 {
 {
-  MESSAGE("AffectedElemGroupsInRegion");
+  SMESH_TRY;
   SMESH::ListOfGroups_var aListOfGroups = new SMESH::ListOfGroups();
   SMESH::ListOfGroups_var aListOfGroups = new SMESH::ListOfGroups();
-  bool isEdgeGroup = false;
-  bool isFaceGroup = false;
-  bool isVolumeGroup = false;
-  SMESH::SMESH_Group_var aNewEdgeGroup = myMesh_i->CreateGroup(SMESH::EDGE, "affectedEdges");
-  SMESH::SMESH_Group_var aNewFaceGroup = myMesh_i->CreateGroup(SMESH::FACE, "affectedFaces");
-  SMESH::SMESH_Group_var aNewVolumeGroup = myMesh_i->CreateGroup(SMESH::VOLUME, "affectedVolumes");
+  SMESH::SMESH_Group_var aNewEdgeGroup   = SMESH::SMESH_Group::_nil();
+  SMESH::SMESH_Group_var aNewFaceGroup   = SMESH::SMESH_Group::_nil();
+  SMESH::SMESH_Group_var aNewVolumeGroup = SMESH::SMESH_Group::_nil();
 
   initData();
 
 
   initData();
 
@@ -6080,135 +6813,149 @@ SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theEl
 
   SMESHDS_Mesh* aMeshDS = getMeshDS();
   TIDSortedElemSet anElems, aNodes;
 
   SMESHDS_Mesh* aMeshDS = getMeshDS();
   TIDSortedElemSet anElems, aNodes;
-  listOfGroupToSet(theElems, aMeshDS, anElems, false);
+  bool isNodeGrp = theElems.length() ? theElems[0]->GetType() == SMESH::NODE : false;
+  listOfGroupToSet(theElems, aMeshDS, anElems, isNodeGrp);
   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true);
 
   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape(theShape);
   TIDSortedElemSet anAffected;
   bool aResult = aMeshEditor.AffectedElemGroupsInRegion(anElems, aNodes, aShape, anAffected);
 
   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true);
 
   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape(theShape);
   TIDSortedElemSet anAffected;
   bool aResult = aMeshEditor.AffectedElemGroupsInRegion(anElems, aNodes, aShape, anAffected);
 
+  declareMeshModified( /*isReComputeSafe=*/ !aResult );
 
 
-  myMesh->GetMeshDS()->Modified();
   TPythonDump pyDump;
   TPythonDump pyDump;
-  if (aResult)
+  if ( aResult && anAffected.size() > 0 )
+  {
+    SMESH::long_array_var volumeIds = new SMESH::long_array;
+    SMESH::long_array_var   faceIds = new SMESH::long_array;
+    SMESH::long_array_var   edgeIds = new SMESH::long_array;
+    volumeIds->length( anAffected.size() );
+    faceIds  ->length( anAffected.size() );
+    edgeIds  ->length( anAffected.size() );
+
+    int ivol = 0;
+    int iface = 0;
+    int iedge = 0;
+    TIDSortedElemSet::const_iterator eIt = anAffected.begin();
+    for (; eIt != anAffected.end(); ++eIt)
     {
     {
-      myMesh->SetIsModified(true);
-
-      int lg = anAffected.size();
-      MESSAGE("lg="<< lg);
-      SMESH::long_array_var volumeIds = new SMESH::long_array;
-      volumeIds->length(lg);
-      SMESH::long_array_var faceIds = new SMESH::long_array;
-      faceIds->length(lg);
-      SMESH::long_array_var edgeIds = new SMESH::long_array;
-      edgeIds->length(lg);
-      int ivol = 0;
-      int iface = 0;
-      int iedge = 0;
-
-      TIDSortedElemSet::const_iterator eIt = anAffected.begin();
-      for (; eIt != anAffected.end(); ++eIt)
-        {
-          const SMDS_MeshElement* anElem = *eIt;
-          if (!anElem)
-            continue;
-          int elemId = anElem->GetID();
-          if (myMesh->GetElementType(elemId, true) == SMDSAbs_Volume)
-            volumeIds[ivol++] = elemId;
-          else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Face)
-            faceIds[iface++] = elemId;
-          else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Edge)
-            edgeIds[iedge++] = elemId;
-        }
-      volumeIds->length(ivol);
-      faceIds->length(iface);
-      edgeIds->length(iedge);
+      const SMDS_MeshElement* anElem = *eIt;
+      int elemId = anElem->GetID();
+      switch ( anElem->GetType() ) {
+      case SMDSAbs_Volume: volumeIds[ivol++] = elemId; break;
+      case SMDSAbs_Face:    faceIds[iface++] = elemId; break;
+      case SMDSAbs_Edge:    edgeIds[iedge++] = elemId; break;
+      default:;
+      }
+    }
+    volumeIds->length(ivol);
+    faceIds->length(iface);
+    edgeIds->length(iedge);
 
 
+    int nbGroups = 0;
+    if ( ivol > 0 )
+    {
+      aNewVolumeGroup = myMesh_i->CreateGroup(SMESH::VOLUME,
+                                              GenerateGroupName("affectedVolumes").c_str());
       aNewVolumeGroup->Add(volumeIds);
       aNewVolumeGroup->Add(volumeIds);
+      aListOfGroups->length( nbGroups+1 );
+      aListOfGroups[ nbGroups++ ] = aNewVolumeGroup._retn();
+    }
+    if ( iface > 0 )
+    {
+      aNewFaceGroup = myMesh_i->CreateGroup(SMESH::FACE,
+                                            GenerateGroupName("affectedFaces").c_str());
       aNewFaceGroup->Add(faceIds);
       aNewFaceGroup->Add(faceIds);
+      aListOfGroups->length( nbGroups+1 );
+      aListOfGroups[ nbGroups++ ] = aNewFaceGroup._retn();
+    }
+    if ( iedge > 0 )
+    {
+      aNewEdgeGroup = myMesh_i->CreateGroup(SMESH::EDGE,
+                                            GenerateGroupName("affectedEdges").c_str());
       aNewEdgeGroup->Add(edgeIds);
       aNewEdgeGroup->Add(edgeIds);
-      isVolumeGroup = (aNewVolumeGroup->Size() > 0);
-      isFaceGroup = (aNewFaceGroup->Size() > 0);
-      isEdgeGroup = (aNewEdgeGroup->Size() > 0);
+      aListOfGroups->length( nbGroups+1 );
+      aListOfGroups[ nbGroups++ ] = aNewEdgeGroup._retn();
     }
     }
-
-  int nbGroups = 0;
-  if (isEdgeGroup)
-    nbGroups++;
-  if (isFaceGroup)
-    nbGroups++;
-  if (isVolumeGroup)
-    nbGroups++;
-  aListOfGroups->length(nbGroups);
-
-  int i = 0;
-  if (isEdgeGroup)
-    aListOfGroups[i++] = aNewEdgeGroup._retn();
-  if (isFaceGroup)
-    aListOfGroups[i++] = aNewFaceGroup._retn();
-  if (isVolumeGroup)
-    aListOfGroups[i++] = aNewVolumeGroup._retn();
+  }
 
   // Update Python script
 
 
   // Update Python script
 
-  pyDump << "[ ";
-  if (isEdgeGroup)
-    pyDump << aNewEdgeGroup << ", ";
-  if (isFaceGroup)
-    pyDump << aNewFaceGroup << ", ";
-  if (isVolumeGroup)
-    pyDump << aNewVolumeGroup << ", ";
-  pyDump << "] = ";
-  pyDump << this << ".AffectedElemGroupsInRegion( " << &theElems << ", " << &theNodesNot << ", " << theShape << " )";
+  pyDump << aListOfGroups << " = " << this << ".AffectedElemGroupsInRegion( "
+         << &theElems << ", " << &theNodesNot << ", " << theShape << " )";
 
   return aListOfGroups._retn();
 
   return aListOfGroups._retn();
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
 }
 
 //================================================================================
 /*!
   \brief Generated skin mesh (containing 2D cells) from 3D mesh
 }
 
 //================================================================================
 /*!
   \brief Generated skin mesh (containing 2D cells) from 3D mesh
-   The created 2D mesh elements based on nodes of free faces of boundary volumes
+  The created 2D mesh elements based on nodes of free faces of boundary volumes
   \return TRUE if operation has been completed successfully, FALSE otherwise
 */
 //================================================================================
 
 CORBA::Boolean SMESH_MeshEditor_i::Make2DMeshFrom3D()
   \return TRUE if operation has been completed successfully, FALSE otherwise
 */
 //================================================================================
 
 CORBA::Boolean SMESH_MeshEditor_i::Make2DMeshFrom3D()
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   bool aResult = getEditor().Make2DMeshFrom3D();
   initData();
 
   bool aResult = getEditor().Make2DMeshFrom3D();
-  myMesh->GetMeshDS()->Modified();
+
   TPythonDump() << "isDone = " << this << ".Make2DMeshFrom3D()";
   TPythonDump() << "isDone = " << this << ".Make2DMeshFrom3D()";
+
+  declareMeshModified( /*isReComputeSafe=*/ !aResult );
   return aResult;
   return aResult;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return false;
 }
 
 //================================================================================
 /*!
  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
 }
 
 //================================================================================
 /*!
  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
- * The list of groups must describe a partition of the mesh volumes.
+ * The list of groups must contain at least two groups. The groups have to be disjoint:
+ * no common element into two different groups.
  * The nodes of the internal faces at the boundaries of the groups are doubled.
  * The nodes of the internal faces at the boundaries of the groups are doubled.
- * In option, the internal faces are replaced by flat elements.
- * Triangles are transformed in prisms, and quadrangles in hexahedrons.
+ * Optionally, the internal faces are replaced by flat elements.
+ * Triangles are transformed into prisms, and quadrangles into hexahedrons.
  * The flat elements are stored in groups of volumes.
  * The flat elements are stored in groups of volumes.
- * @param theDomains - list of groups of volumes
- * @param createJointElems - if TRUE, create the elements
- * @return TRUE if operation has been completed successfully, FALSE otherwise
+ * These groups are named according to the position of the group in the list:
+ * the group j_n_p is the group of the flat elements that are built between the group #n and the group #p in the list.
+ * If there is no shared faces between the group #n and the group #p in the list, the group j_n_p is not created.
+ * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
+ * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
+ * \param theDomains - list of groups of volumes
+ * \param createJointElems - if TRUE, create the elements
+ * \param onAllBoundaries - if TRUE, the nodes and elements are also created on
+ *        the boundary between \a theDomains and the rest mesh
+ * \return TRUE if operation has been completed successfully, FALSE otherwise
  */
 //================================================================================
 
  */
 //================================================================================
 
-CORBA::Boolean SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::ListOfGroups& theDomains,
-                                                                 CORBA::Boolean createJointElems )
+CORBA::Boolean
+SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::ListOfGroups& theDomains,
+                                                  CORBA::Boolean             createJointElems,
+                                                  CORBA::Boolean             onAllBoundaries )
   throw (SALOME::SALOME_Exception)
 {
   throw (SALOME::SALOME_Exception)
 {
-  bool aResult = false;
+  bool isOK = false;
 
   SMESH_TRY;
   initData();
 
   SMESHDS_Mesh* aMeshDS = getMeshDS();
 
 
   SMESH_TRY;
   initData();
 
   SMESHDS_Mesh* aMeshDS = getMeshDS();
 
+  // MESSAGE("theDomains.length = "<<theDomains.length());
+  if ( theDomains.length() <= 1 && !onAllBoundaries )
+    THROW_SALOME_CORBA_EXCEPTION("At least 2 groups are required.", SALOME::BAD_PARAM);
+
   vector<TIDSortedElemSet> domains;
   vector<TIDSortedElemSet> domains;
-  domains.clear();
+  domains.resize( theDomains.length() );
 
   for ( int i = 0, n = theDomains.length(); i < n; i++ )
   {
 
   for ( int i = 0, n = theDomains.length(); i < n; i++ )
   {
@@ -6217,26 +6964,25 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::Li
     {
 //      if ( aGrp->GetType() != SMESH::VOLUME )
 //        THROW_SALOME_CORBA_EXCEPTION("Not a volume group", SALOME::BAD_PARAM);
     {
 //      if ( aGrp->GetType() != SMESH::VOLUME )
 //        THROW_SALOME_CORBA_EXCEPTION("Not a volume group", SALOME::BAD_PARAM);
-      TIDSortedElemSet domain;
-      domain.clear();
-      domains.push_back(domain);
       SMESH::long_array_var anIDs = aGrp->GetIDs();
       arrayToSet( anIDs, aMeshDS, domains[ i ], SMDSAbs_All );
     }
   }
 
       SMESH::long_array_var anIDs = aGrp->GetIDs();
       arrayToSet( anIDs, aMeshDS, domains[ i ], SMDSAbs_All );
     }
   }
 
-  aResult = getEditor().DoubleNodesOnGroupBoundaries( domains, createJointElems );
+  isOK = getEditor().DoubleNodesOnGroupBoundaries( domains, createJointElems, onAllBoundaries );
   // TODO publish the groups of flat elements in study
 
   // TODO publish the groups of flat elements in study
 
-  myMesh->GetMeshDS()->Modified();
+  declareMeshModified( /*isReComputeSafe=*/ !isOK );
 
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodesOnGroupBoundaries( " << &theDomains
 
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodesOnGroupBoundaries( " << &theDomains
-      << ", " << createJointElems << " )";
+                << ", " << createJointElems << ", " << onAllBoundaries << " )";
 
   SMESH_CATCH( SMESH::throwCorbaException );
 
 
   SMESH_CATCH( SMESH::throwCorbaException );
 
-  return aResult;
+  myMesh_i->CreateGroupServants(); // publish created groups if any
+
+  return isOK;
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -6251,11 +6997,13 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::Li
  */
 //================================================================================
 
  */
 //================================================================================
 
-CORBA::Boolean SMESH_MeshEditor_i::CreateFlatElementsOnFacesGroups( const SMESH::ListOfGroups& theGroupsOfFaces )
+CORBA::Boolean
+SMESH_MeshEditor_i::CreateFlatElementsOnFacesGroups( const SMESH::ListOfGroups& theGroupsOfFaces )
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   initData();
 
-
   SMESHDS_Mesh* aMeshDS = getMeshDS();
 
   vector<TIDSortedElemSet> faceGroups;
   SMESHDS_Mesh* aMeshDS = getMeshDS();
 
   vector<TIDSortedElemSet> faceGroups;
@@ -6277,23 +7025,32 @@ CORBA::Boolean SMESH_MeshEditor_i::CreateFlatElementsOnFacesGroups( const SMESH:
   bool aResult = getEditor().CreateFlatElementsOnFacesGroups( faceGroups );
   // TODO publish the groups of flat elements in study
 
   bool aResult = getEditor().CreateFlatElementsOnFacesGroups( faceGroups );
   // TODO publish the groups of flat elements in study
 
-  myMesh->GetMeshDS()->Modified();
+  declareMeshModified( /*isReComputeSafe=*/ !aResult );
 
   // Update Python script
 
   // Update Python script
-  TPythonDump() << "isDone = " << this << ".CreateFlatElementsOnFacesGroups( " << &theGroupsOfFaces << " )";
+  TPythonDump() << this << ".CreateFlatElementsOnFacesGroups( " << &theGroupsOfFaces << " )";
   return aResult;
   return aResult;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return false;
 }
 
 }
 
+//================================================================================
 /*!
 /*!
- *  \brief identify all the elements around a geom shape, get the faces delimiting the hole
- *  Build groups of volume to remove, groups of faces to replace on the skin of the object,
- *  groups of faces to remove inside the object, (idem edges).
- *  Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape)
+ *  \brief Identify all the elements around a geom shape, get the faces delimiting
+ *         the hole.
+ *
+ *  Build groups of volume to remove, groups of faces to replace on the skin of the
+ *  object, groups of faces to remove inside the object, (idem edges).
+ *  Build ordered list of nodes at the border of each group of faces to replace
+ *  (to be used to build a geom subshape).
  */
  */
-void SMESH_MeshEditor_i::CreateHoleSkin(CORBA::Double radius,
-                                        GEOM::GEOM_Object_ptr theShape,
-                                        const char* groupName,
-                                        const SMESH::double_array& theNodesCoords,
+//================================================================================
+
+void SMESH_MeshEditor_i::CreateHoleSkin(CORBA::Double                  radius,
+                                        GEOM::GEOM_Object_ptr          theShape,
+                                        const char*                    groupName,
+                                        const SMESH::double_array&     theNodesCoords,
                                         SMESH::array_of_long_array_out GroupsOfNodes)
   throw (SALOME::SALOME_Exception)
 {
                                         SMESH::array_of_long_array_out GroupsOfNodes)
   throw (SALOME::SALOME_Exception)
 {
@@ -6305,10 +7062,10 @@ void SMESH_MeshEditor_i::CreateHoleSkin(CORBA::Double radius,
 
   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
   if ( !theNodeSearcher )
 
   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
   if ( !theNodeSearcher )
-    theNodeSearcher = aMeshEditor.GetNodeSearcher();
+    theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
 
   vector<double> nodesCoords;
 
   vector<double> nodesCoords;
-  for (int i = 0; i < theNodesCoords.length(); i++)
+  for ( CORBA::ULong i = 0; i < theNodesCoords.length(); i++)
   {
     nodesCoords.push_back( theNodesCoords[i] );
   }
   {
     nodesCoords.push_back( theNodesCoords[i] );
   }
@@ -6338,7 +7095,6 @@ void SMESH_MeshEditor_i::CreateHoleSkin(CORBA::Double radius,
   SMESH_CATCH( SMESH::throwCorbaException );
 }
 
   SMESH_CATCH( SMESH::throwCorbaException );
 }
 
-
 // issue 20749 ===================================================================
 /*!
  * \brief Creates missing boundary elements
 // issue 20749 ===================================================================
 /*!
  * \brief Creates missing boundary elements
@@ -6364,7 +7120,9 @@ SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource,
                                      CORBA::Boolean            toCopyElements,
                                      CORBA::Boolean            toCopyExistingBondary,
                                      SMESH::SMESH_Group_out    group)
                                      CORBA::Boolean            toCopyElements,
                                      CORBA::Boolean            toCopyExistingBondary,
                                      SMESH::SMESH_Group_out    group)
+  throw (SALOME::SALOME_Exception)
 {
 {
+  SMESH_TRY;
   initData();
 
   if ( dim > SMESH::BND_1DFROM2D )
   initData();
 
   if ( dim > SMESH::BND_1DFROM2D )
@@ -6417,7 +7175,7 @@ SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource,
   else
     pyDump << mesh_var << ", ";
   if ( group_var->_is_nil() )
   else
     pyDump << mesh_var << ", ";
   if ( group_var->_is_nil() )
-    pyDump << "_NoneGroup = "; // assignment to None is forbiden
+    pyDump << "_NoneGroup = "; // assignment to None is forbidden
   else
     pyDump << group_var << " = ";
   pyDump << this << ".MakeBoundaryMesh( "
   else
     pyDump << group_var << " = ";
   pyDump << this << ".MakeBoundaryMesh( "
@@ -6430,6 +7188,9 @@ SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource,
 
   group = group_var._retn();
   return mesh_var._retn();
 
   group = group_var._retn();
   return mesh_var._retn();
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return SMESH::SMESH_Mesh::_nil();
 }
 
 //================================================================================
 }
 
 //================================================================================
@@ -6458,28 +7219,27 @@ CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
                                                      SMESH::SMESH_Group_out group)
   throw (SALOME::SALOME_Exception)
 {
                                                      SMESH::SMESH_Group_out group)
   throw (SALOME::SALOME_Exception)
 {
-  Unexpect aCatch(SALOME_SalomeException);
-
+  SMESH_TRY;
   initData();
 
   if ( dim > SMESH::BND_1DFROM2D )
     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
 
   // separate groups belonging to this and other mesh
   initData();
 
   if ( dim > SMESH::BND_1DFROM2D )
     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
 
   // separate groups belonging to this and other mesh
-  SMESH::ListOfIDSources_var groupsOfThisMesh = new SMESH::ListOfIDSources;
+  SMESH::ListOfIDSources_var groupsOfThisMesh  = new SMESH::ListOfIDSources;
   SMESH::ListOfIDSources_var groupsOfOtherMesh = new SMESH::ListOfIDSources;
   SMESH::ListOfIDSources_var groupsOfOtherMesh = new SMESH::ListOfIDSources;
-  groupsOfThisMesh->length( groups.length() );
+  groupsOfThisMesh ->length( groups.length() );
   groupsOfOtherMesh->length( groups.length() );
   int nbGroups = 0, nbGroupsOfOtherMesh = 0;
   groupsOfOtherMesh->length( groups.length() );
   int nbGroups = 0, nbGroupsOfOtherMesh = 0;
-  for ( int i = 0; i < groups.length(); ++i )
+  for ( CORBA::ULong i = 0; i < groups.length(); ++i )
   {
     SMESH::SMESH_Mesh_var m = groups[i]->GetMesh();
   {
     SMESH::SMESH_Mesh_var m = groups[i]->GetMesh();
-    if ( myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
+    if ( !m->_is_nil() && myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
       groupsOfOtherMesh[ nbGroupsOfOtherMesh++ ] = groups[i];
     else
       groupsOfThisMesh[ nbGroups++ ] = groups[i];
     if ( SMESH::DownCast<SMESH_Mesh_i*>( groups[i] ))
       groupsOfOtherMesh[ nbGroupsOfOtherMesh++ ] = groups[i];
     else
       groupsOfThisMesh[ nbGroups++ ] = groups[i];
     if ( SMESH::DownCast<SMESH_Mesh_i*>( groups[i] ))
-      THROW_SALOME_CORBA_EXCEPTION("expect a group but recieve a mesh", SALOME::BAD_PARAM);
+      THROW_SALOME_CORBA_EXCEPTION("expected a group but received a mesh", SALOME::BAD_PARAM);
   }
   groupsOfThisMesh->length( nbGroups );
   groupsOfOtherMesh->length( nbGroupsOfOtherMesh );
   }
   groupsOfThisMesh->length( nbGroups );
   groupsOfOtherMesh->length( nbGroupsOfOtherMesh );
@@ -6522,7 +7282,7 @@ CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
   // group of boundary elements
   SMESH_Group* smesh_group = 0;
   SMDSAbs_ElementType elemType = (dim == SMESH::BND_2DFROM3D) ? SMDSAbs_Volume : SMDSAbs_Face;
   // group of boundary elements
   SMESH_Group* smesh_group = 0;
   SMDSAbs_ElementType elemType = (dim == SMESH::BND_2DFROM3D) ? SMDSAbs_Volume : SMDSAbs_Face;
-  if ( strlen(groupName) )
+  if ( strlen( groupName ))
   {
     SMESH::ElementType groupType = SMESH::ElementType( int(elemType)-1 );
     group_var = mesh_i->CreateGroup( groupType, groupName );
   {
     SMESH::ElementType groupType = SMESH::ElementType( int(elemType)-1 );
     group_var = mesh_i->CreateGroup( groupType, groupName );
@@ -6573,7 +7333,7 @@ CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
   else
     pyDump << mesh_var << ", ";
   if ( group_var->_is_nil() )
   else
     pyDump << mesh_var << ", ";
   if ( group_var->_is_nil() )
-    pyDump << "_NoneGroup = "; // assignment to None is forbiden
+    pyDump << "_NoneGroup = "; // assignment to None is forbidden
   else
     pyDump << group_var << " = ";
   pyDump << this << ".MakeBoundaryElements( "
   else
     pyDump << group_var << " = ";
   pyDump << this << ".MakeBoundaryElements( "
@@ -6586,4 +7346,189 @@ CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
   mesh  = mesh_var._retn();
   group = group_var._retn();
   return nbAdded;
   mesh  = mesh_var._retn();
   group = group_var._retn();
   return nbAdded;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
+
+//================================================================================
+/*!
+ * \brief Create a polyline consisting of 1D mesh elements each lying on a 2D element of
+ *        the initial mesh. Positions of new nodes are found by cutting the mesh by the
+ *        plane passing through pairs of points specified by each PolySegment structure.
+ *        If there are several paths connecting a pair of points, the shortest path is
+ *        selected by the module. Position of the cutting plane is defined by the two
+ *        points and an optional vector lying on the plane specified by a PolySegment.
+ *        By default the vector is defined by Mesh module as following. A middle point
+ *        of the two given points is computed. The middle point is projected to the mesh.
+ *        The vector goes from the middle point to the projection point. In case of planar
+ *        mesh, the vector is normal to the mesh.
+ *  \param [inout] segments - PolySegment's defining positions of cutting planes.
+ *        Return the used vector and position of the middle point.
+ *  \param [in] groupName - optional name of a group where created mesh segments will
+ *        be added.
+ */
+//================================================================================
+
+void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments,
+                                      const char*                theGroupName)
+  throw (SALOME::SALOME_Exception)
+{
+  if ( theSegments.length() == 0 )
+    THROW_SALOME_CORBA_EXCEPTION("No segments given", SALOME::BAD_PARAM );
+  if ( myMesh->NbFaces() == 0 )
+    THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM );
+
+  SMESH_TRY;
+  initData(/*deleteSearchers=*/false);
+
+  SMESHDS_Group* groupDS = 0;
+  SMESHDS_Mesh*   meshDS = getMeshDS();
+  if ( myIsPreviewMode ) // copy faces to the tmp mesh
+  {
+    TPreviewMesh * tmpMesh = getPreviewMesh( SMDSAbs_Edge );
+    SMDS_ElemIteratorPtr faceIt = getMeshDS()->elementsIterator( SMDSAbs_Face );
+    while ( faceIt->more() )
+      tmpMesh->Copy( faceIt->next() );
+    meshDS = tmpMesh->GetMeshDS();
+  }
+  else if ( theGroupName[0] ) // find/create a group of segments
+  {
+    // SMESH_Mesh::GroupIteratorPtr grpIt = myMesh->GetGroups();
+    // while ( !groupDS && grpIt->more() )
+    // {
+    //   SMESH_Group* group = grpIt->next();
+    //   if ( group->GetGroupDS()->GetType() == SMDSAbs_Edge &&
+    //        strcmp( group->GetName(), theGroupName ) == 0 )
+    //   {
+    //     groupDS = dynamic_cast< SMESHDS_Group* >( group->GetGroupDS() );
+    //   }
+    // }
+    if ( !groupDS )
+    {
+      SMESH::SMESH_Group_var groupVar = myMesh_i->CreateGroup( SMESH::EDGE, theGroupName );
+
+      if ( SMESH_Group_i* groupImpl = SMESH::DownCast<SMESH_Group_i*>( groupVar ))
+        groupDS = dynamic_cast< SMESHDS_Group* >( groupImpl->GetGroupDS() );
+    }
+  }
+
+  // convert input polySegments
+  SMESH_MeshAlgos::TListOfPolySegments segments( theSegments.length() );
+  for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
+  {
+    SMESH::PolySegment&            segIn = theSegments[ i ];
+    SMESH_MeshAlgos::PolySegment& segOut = segments[ i ];
+    segOut.myNode1[0] = meshDS->FindNode( segIn.node1ID1 );
+    segOut.myNode2[0] = meshDS->FindNode( segIn.node1ID2 );
+    segOut.myNode1[1] = meshDS->FindNode( segIn.node2ID1 );
+    segOut.myNode2[1] = meshDS->FindNode( segIn.node2ID2 );
+    segOut.myXYZ[0].SetCoord( segIn.xyz1.x,
+                              segIn.xyz1.y,
+                              segIn.xyz1.z);
+    segOut.myXYZ[1].SetCoord( segIn.xyz2.x,
+                              segIn.xyz2.y,
+                              segIn.xyz2.z);
+    segOut.myVector.SetCoord( segIn.vector.PS.x,
+                              segIn.vector.PS.y,
+                              segIn.vector.PS.z );
+  }
+
+  // get a static ElementSearcher
+  SMESH::SMESH_IDSource_var idSource = SMESH::SMESH_IDSource::_narrow( myMesh_i->_this() );
+  theSearchersDeleter.Set( myMesh, getPartIOR( idSource, SMESH::FACE ));
+  if ( !theElementSearcher )
+    theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
+
+  // compute
+  std::vector<const SMDS_MeshElement*> newEdges;
+  std::vector<const SMDS_MeshNode*>    newNodes;
+  SMESH_MeshAlgos::MakePolyLine( meshDS, segments, newEdges, newNodes,
+                                 groupDS ? &groupDS->SMDSGroup() : 0,
+                                 theElementSearcher );
+
+  const_cast< SMESH_SequenceOfElemPtr& >( getEditor().GetLastCreatedElems() ).
+    swap( newEdges );
+  const_cast< SMESH_SequenceOfElemPtr& >( getEditor().GetLastCreatedNodes() ).
+    assign( newNodes.begin(), newNodes.end() );
+
+  // return vectors
+  if ( myIsPreviewMode )
+  {
+    for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
+    {
+      SMESH::PolySegment&           segOut = theSegments[ i ];
+      SMESH_MeshAlgos::PolySegment& segIn = segments[ i ];
+      segOut.vector.PS.x = segIn.myVector.X();
+      segOut.vector.PS.y = segIn.myVector.Y();
+      segOut.vector.PS.z = segIn.myVector.Z();
+    }
+  }
+  else
+  {
+    TPythonDump() << "_segments = []";
+    for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
+    {
+      SMESH::PolySegment& segIn = theSegments[ i ];
+      TPythonDump() << "_segments.append( SMESH.PolySegment( "
+                    << segIn.node1ID1 << ", "
+                    << segIn.node1ID2 << ", "
+                    << segIn.node2ID1 << ", "
+                    << segIn.node2ID2 << ", "
+                    << "smeshBuilder.MakeDirStruct( "
+                    << segIn.vector.PS.x << ", "
+                    << segIn.vector.PS.y << ", "
+                    << segIn.vector.PS.z << ")))";
+    }
+    TPythonDump() << this << ".MakePolyLine( _segments, '" << theGroupName << "')";
+  }
+  meshDS->Modified();
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return;
+}
+
+//================================================================================
+/*!
+ * \brief Create a slot of given width around given 1D elements lying on a triangle mesh.
+ *        The slot is consrtucted by cutting faces by cylindrical surfaces made
+ *        around each segment. Segments are expected to be created by MakePolyLine().
+ * \return Edges located at the slot boundary
+ */
+//================================================================================
+
+SMESH::ListOfEdges* SMESH_MeshEditor_i::MakeSlot(SMESH::SMESH_GroupBase_ptr theSegments,
+                                                 CORBA::Double              theWidth)
+  throw (SALOME::SALOME_Exception)
+{
+  if ( CORBA::is_nil( theSegments ) ||
+       theSegments->GetType() != SMESH::EDGE )
+    THROW_SALOME_CORBA_EXCEPTION("No segments given", SALOME::BAD_PARAM );
+  if ( myMesh->NbFaces() == 0 )
+    THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM );
+
+  SMESH::ListOfEdges_var resultEdges = new SMESH::ListOfEdges;
+
+  SMESH_TRY;
+  initData(/*deleteSearchers=*/false);
+
+  SMESHDS_Mesh* meshDS = getMeshDS();
+
+  std::vector< SMESH_MeshAlgos::Edge > edges =
+    SMESH_MeshAlgos::MakeSlot( SMESH_Mesh_i::GetElements( theSegments, SMESH::EDGE ),
+                               theWidth, meshDS );
+
+  resultEdges->length( edges.size() );
+  for ( size_t i = 0; i < edges.size(); ++i )
+  {
+    resultEdges[ i ].node1  = edges[i]._node1->GetID();
+    resultEdges[ i ].node2  = edges[i]._node2->GetID();
+    resultEdges[ i ].medium = edges[i]._medium ? edges[i]._medium->GetID() : 0;
+  }
+
+  meshDS->Modified();
+  SMESH_CATCH( SMESH::throwCorbaException );
+
+  TSearchersDeleter::Delete(); // face searcher becomes invalid as some faces were removed
+
+  return resultEdges._retn();
 }
 }