Salome HOME
Make SetNodeOnEdge() tell a valid range if U is invalid
[modules/smesh.git] / src / SMESH_I / SMESH_MeshEditor_i.cxx
index 72ce66df63446b73c1e25b9bd2a4e4ec1131a007..b813fc37b4bd10dce08a26bf9db49edab06af1f1 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2016  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
@@ -42,7 +42,6 @@
 #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"
@@ -102,7 +101,7 @@ namespace MeshEditor_I {
     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;
     }
@@ -179,7 +178,7 @@ namespace MeshEditor_I {
 
   //=============================================================================
   /*!
-   * \brief Deleter of theNodeSearcher at any compute event occurred
+   * \brief Deleter of theNodeSearcher and theElementSearcher at any compute event occurred
    */
   //=============================================================================
 
@@ -299,33 +298,35 @@ namespace MeshEditor_I {
    */
   //================================================================================
 
-  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;
-    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 ( CORBA::ULong 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( ))
+      for ( SMDS_NodeIteratorPtr nIt = theMeshDS->nodesIterator(); nIt->more(); )
         if ( const SMDS_MeshElement * elem = nIt->next() )
           theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
     }
     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());
+      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());
+      }
     }
   }
 
@@ -382,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
@@ -534,7 +537,9 @@ SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData()
     SMESHDS_Mesh* aMeshDS;
     std::unique_ptr< SMESH_MeshPartDS > aMeshPartDS;
     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 {
@@ -680,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->hasBadMesh = !errIn->myBadElements.empty();
+    errOut->hasBadMesh = errIn->HasBadElems();
   }
   else
   {
@@ -1385,8 +1390,11 @@ void SMESH_MeshEditor_i::SetNodeOnEdge(CORBA::Long NodeID, CORBA::Long EdgeID,
   Standard_Real f,l;
   BRep_Tool::Range( TopoDS::Edge( shape ), f,l);
   if ( paramOnEdge < f || paramOnEdge > l )
-    THROW_SALOME_CORBA_EXCEPTION("Invalid paramOnEdge", SALOME::BAD_PARAM);
-
+  {
+    SMESH_Comment txt("Invalid paramOnEdge. It must vary in range [ ");
+    txt << f << ", " << l << " ]";
+    THROW_SALOME_CORBA_EXCEPTION(txt.c_str(), SALOME::BAD_PARAM);
+  }
   mesh->SetNodeOnEdge( node, EdgeID, paramOnEdge );
 
   myMesh->SetIsModified( true );
@@ -1429,14 +1437,11 @@ void SMESH_MeshEditor_i::SetNodeOnFace(CORBA::Long NodeID, CORBA::Long FaceID,
                  v > surf.LastVParameter() );
 
   if ( isOut ) {
-#ifdef _DEBUG_
-    MESSAGE ( "FACE " << FaceID << " (" << u << "," << v << ") out of "
-              << " u( " <<  surf.FirstUParameter()
-              << "," <<  surf.LastUParameter()
-              << ") v( " <<  surf.FirstVParameter()
-              << "," <<  surf.LastVParameter() << ")" );
-#endif
-    THROW_SALOME_CORBA_EXCEPTION("Invalid UV", SALOME::BAD_PARAM);
+    SMESH_Comment txt("Invalid UV. U must vary in range [ ");
+    txt << surf.FirstUParameter() << ", " << surf.LastUParameter() << " ], ";
+    txt << "V must vary in range [ ";
+    txt << surf.FirstVParameter() << ", " << surf.LastVParameter() << " ]";
+    THROW_SALOME_CORBA_EXCEPTION(txt.c_str(), SALOME::BAD_PARAM);
   }
 
   mesh->SetNodeOnFace( node, FaceID, u, v );
@@ -2065,9 +2070,10 @@ void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems,
 
   ::SMESH_MeshEditor::TFacetOfElem elemSet;
   const int noneFacet = -1;
-  SMDS_ElemIteratorPtr volIt = myMesh_i->GetElements( elems, SMESH::VOLUME );
-  while( volIt->more() )
-    elemSet.insert( elemSet.end(), make_pair( volIt->next(), noneFacet ));
+  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()
@@ -2108,6 +2114,7 @@ void SMESH_MeshEditor_i::SplitHexahedraIntoPrisms( SMESH::SMESH_IDSource_ptr  el
                             facetToSplitNormal.PS.y,
                             facetToSplitNormal.PS.z ));
   TIDSortedElemSet elemSet;
+  prepareIdSource( elems );
   SMESH::long_array_var anElementsId = elems->GetIDs();
   SMDS_MeshElement::GeomFilter filter( SMDSGeom_HEXA );
   arrayToSet( anElementsId, getMeshDS(), elemSet, SMDSAbs_Volume, &filter );
@@ -2422,8 +2429,8 @@ SMESH_MeshEditor_i::RotationSweepObjects(const SMESH::ListOfIDSources & theNodes
 
   TIDSortedElemSet elemsNodes[2];
   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
-    SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
-    while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
+    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 );
@@ -2489,7 +2496,8 @@ namespace MeshEditor_I
     bool myIsExtrusionByNormal;
 
     static int makeFlags( CORBA::Boolean MakeGroups,
-                          CORBA::Boolean LinearVariation = false,
+                          CORBA::Boolean ScaleVariation = false,
+                          CORBA::Boolean AngleVariation = false,
                           CORBA::Boolean ByAverageNormal = false,
                           CORBA::Boolean UseInputElemsOnly = false,
                           CORBA::Long    Flags = 0,
@@ -2498,7 +2506,8 @@ namespace MeshEditor_I
       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 ( LinearVariation  ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_SCALE_LINEAR_VARIATION;
+      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;
     }
@@ -2506,7 +2515,9 @@ namespace MeshEditor_I
     ExtrusionParams(const SMESH::DirStruct &    theDir,
                     CORBA::Long                 theNbOfSteps,
                     const SMESH::double_array & theScaleFactors,
-                    CORBA::Boolean              theLinearVariation,
+                    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,
@@ -2514,8 +2525,9 @@ namespace MeshEditor_I
                                                 theDir.PS.z ),
                                         theNbOfSteps,
                                         toList( theScaleFactors ),
+                                        toList( theAngles ),
                                         TBasePoint( theBasePoint ),
-                                        makeFlags( theMakeGroups, theLinearVariation )),
+                                        makeFlags( theMakeGroups, theScaleVariation, theAngleVariation )),
       myIsExtrusionByNormal( false )
     {
     }
@@ -2530,8 +2542,9 @@ namespace MeshEditor_I
                                                 theDir.PS.z ),
                                         theNbOfSteps,
                                         std::list<double>(),
+                                        std::list<double>(),
                                         0,
-                                        makeFlags( theMakeGroups, false, false, false,
+                                        makeFlags( theMakeGroups, false, false, false, false,
                                                    theExtrFlags, false ),
                                         theSewTolerance ),
       myIsExtrusionByNormal( false )
@@ -2546,7 +2559,7 @@ namespace MeshEditor_I
                     CORBA::Boolean theMakeGroups ):
       ::SMESH_MeshEditor::ExtrusParam ( theStepSize, 
                                         theNbOfSteps,
-                                        makeFlags( theMakeGroups, false,
+                                        makeFlags( theMakeGroups, false, false,
                                                    theByAverageNormal, theUseInputElemsOnly ),
                                         theDim),
       myIsExtrusionByNormal( true )
@@ -2558,8 +2571,6 @@ namespace MeshEditor_I
       Flags() &= ~(::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS);
     }
 
-  private:
-
     static std::list<double> toList( const SMESH::double_array & theScaleFactors )
     {
       std::list<double> scales;
@@ -2568,6 +2579,8 @@ namespace MeshEditor_I
       return scales;
     }
 
+  private:
+
     // structure used to convert SMESH::double_array to gp_XYZ*
     struct TBasePoint
     {
@@ -2596,7 +2609,7 @@ namespace MeshEditor_I
  *  \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 craeted if \a toMakeGroups is true
+ *  \return ListOfGroups - new groups created if \a toMakeGroups is true
  */
 //=======================================================================
 
@@ -2606,22 +2619,24 @@ SMESH_MeshEditor_i::ExtrusionSweepObjects(const SMESH::ListOfIDSources & theNode
                                           const SMESH::ListOfIDSources & theFaces,
                                           const SMESH::DirStruct &       theStepVector,
                                           CORBA::Long                    theNbOfSteps,
+                                          CORBA::Boolean                 theToMakeGroups,
                                           const SMESH::double_array &    theScaleFactors,
-                                          CORBA::Boolean                 theLinearVariation,
+                                          CORBA::Boolean                 theScalesVariation,
                                           const SMESH::double_array &    theBasePoint,
-                                          CORBA::Boolean                 theToMakeGroups)
+                                          const SMESH::double_array &    theAngles,
+                                          CORBA::Boolean                 theAnglesVariation)
   throw (SALOME::SALOME_Exception)
 {
   SMESH_TRY;
   initData();
 
-  ExtrusionParams params( theStepVector, theNbOfSteps, theScaleFactors,
-                          theLinearVariation, theBasePoint, theToMakeGroups );
+  ExtrusionParams params( theStepVector, theNbOfSteps, theScaleFactors, theScalesVariation,
+                          theAngles, theAnglesVariation, theBasePoint, theToMakeGroups );
 
   TIDSortedElemSet elemsNodes[2];
   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
-    SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
-    while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
+    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 );
@@ -2657,12 +2672,17 @@ SMESH_MeshEditor_i::ExtrusionSweepObjects(const SMESH::ListOfIDSources & theNode
   {
     dumpGroupsList( aPythonDump, aGroups );
     aPythonDump << this<< ".ExtrusionSweepObjects( "
-                << theNodes             << ", "
-                << theEdges             << ", "
-                << theFaces             << ", "
-                << theStepVector        << ", "
-                << TVar( theNbOfSteps ) << ", "
-                << theToMakeGroups      << " )";
+                << theNodes                << ", "
+                << theEdges                << ", "
+                << theFaces                << ", "
+                << theStepVector           << ", "
+                << TVar( theNbOfSteps )    << ", "
+                << theToMakeGroups         << ", "
+                << TVar( theScaleFactors ) << ", "
+                << theScalesVariation      << ", "
+                << TVar( theBasePoint )    << ", "
+                << TVar( theAngles )       << ", "
+                << theAnglesVariation      << " )";
   }
   else
   {
@@ -2840,15 +2860,17 @@ SMESH::ListOfGroups*
 SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & theNodes,
                                               const SMESH::ListOfIDSources & theEdges,
                                               const SMESH::ListOfIDSources & theFaces,
-                                              SMESH::SMESH_IDSource_ptr      thePathMesh,
+                                              SMESH::SMESH_IDSource_ptr      thePathObject,
                                               GEOM::GEOM_Object_ptr          thePathShape,
                                               CORBA::Long                    theNodeStart,
                                               CORBA::Boolean                 theHasAngles,
                                               const SMESH::double_array &    theAngles,
-                                              CORBA::Boolean                 theLinearVariation,
+                                              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)
 {
@@ -2858,61 +2880,73 @@ SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & the
   SMESH::ListOfGroups_var aGroups = new SMESH::ListOfGroups;
 
   theError = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE;
-  if ( thePathMesh->_is_nil() )
+  if ( thePathObject->_is_nil() )
     return aGroups._retn();
 
-  // get a sub-mesh
-  SMESH_subMesh* aSubMesh = 0;
-  SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
-  if ( thePathShape->_is_nil() )
+
+  SMDS_ElemIteratorPtr pathEdgesIterator;
+
+  SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathObject );
+  if ( !CORBA::is_nil( thePathShape ) && aMeshImp )
   {
-    // thePathMesh should be either a sub-mesh or a mesh with 1D elements only
-    if ( SMESH_subMesh_i* sm = SMESH::DownCast<SMESH_subMesh_i*>( thePathMesh ))
+    // 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();
+
+    if ( !aSubMesh->GetSubMeshDS() )
     {
-      SMESH::SMESH_Mesh_var mesh = thePathMesh->GetMesh();
-      aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
-      if ( !aMeshImp ) return aGroups._retn();
-      aSubMesh = aMeshImp->GetImpl().GetSubMeshContaining( sm->GetId() );
-      if ( !aSubMesh ) return aGroups._retn();
+      SMESHDS_Mesh * meshDS = aMeshImp->GetImpl().GetMeshDS();
+      meshDS->AddCompoundSubmesh( aShape, TopAbs_EDGE );
+      if ( !aSubMesh->GetSubMeshDS() )
+        return aGroups._retn();
     }
-    else if ( !aMeshImp ||
-              aMeshImp->NbEdges() != aMeshImp->NbElements() )
-    {
+    theError = SMESH::SMESH_MeshEditor::EXTR_PATH_NOT_EDGE;
+    pathEdgesIterator = aSubMesh->GetSubMeshDS()->GetElements();
+    if ( !pathEdgesIterator->more() ||
+         pathEdgesIterator->next()->GetType() != SMDSAbs_Edge )
       return aGroups._retn();
-    }
+
+    pathEdgesIterator = aSubMesh->GetSubMeshDS()->GetElements();
   }
   else
   {
-    if ( !aMeshImp ) return aGroups._retn();
-    TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
-    aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
-    if ( !aSubMesh /*|| !aSubMesh->GetSubMeshDS()*/ )
+    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();
   }
 
-  SMDS_MeshNode* nodeStart =
-    (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(theNodeStart);
-  if ( !nodeStart ) {
-    theError = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
-    return aGroups._retn();
+  if ( !aMeshImp )
+  {
+    SMESH::SMESH_Mesh_var pathMesh = thePathObject->GetMesh();
+    aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( pathMesh );
   }
 
+
+  theError = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
+  const SMDS_MeshNode* nodeStart = aMeshImp->GetImpl().GetMeshDS()->FindNode( theNodeStart );
+  if ( !nodeStart )
+    return aGroups._retn();
+
+
   TIDSortedElemSet elemsNodes[2];
   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
-    SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
-    while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
+    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 );
 
-  list<double> angles;
-  for ( CORBA::ULong i = 0; i < theAngles.length(); i++ ) {
-    angles.push_back( theAngles[i] );
-  }
+  list<double> angles = ExtrusionParams::toList( theAngles );
+  list<double> scales = ExtrusionParams::toList( theScaleFactors );
 
   gp_Pnt refPnt( theRefPoint.x, theRefPoint.y, theRefPoint.z );
+  const gp_Pnt *refPntPtr = theHasRefPoint ? &refPnt : 0;
 
   int nbOldGroups = myMesh->NbGroup();
 
@@ -2927,15 +2961,12 @@ SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & the
     theMakeGroups = false;
   }
 
-  ::SMESH_MeshEditor::Extrusion_Error error;
-  if ( !aSubMesh )
-    error = getEditor().ExtrusionAlongTrack( workElements, &(aMeshImp->GetImpl()), nodeStart,
-                                             theHasAngles, angles, theLinearVariation,
-                                             theHasRefPoint, refPnt, theMakeGroups );
-  else
-    error = getEditor().ExtrusionAlongTrack( workElements, aSubMesh, nodeStart,
-                                             theHasAngles, angles, theLinearVariation,
-                                             theHasRefPoint, refPnt, theMakeGroups );
+  ::SMESH_MeshEditor::Extrusion_Error error =
+      getEditor().ExtrusionAlongTrack( workElements,
+                                       &(aMeshImp->GetImpl()), pathEdgesIterator, nodeStart,
+                                       angles, theAnglesVariation,
+                                       scales, theScalesVariation,
+                                       refPntPtr, theMakeGroups );
 
   declareMeshModified( /*isReComputeSafe=*/true );
   theError = convExtrError( error );
@@ -2957,18 +2988,20 @@ SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & the
                 << theNodes            << ", "
                 << theEdges            << ", "
                 << theFaces            << ", "
-                << thePathMesh         << ", "
+                << thePathObject       << ", "
                 << thePathShape        << ", "
                 << theNodeStart        << ", "
                 << theHasAngles        << ", "
                 << TVar( theAngles )   << ", "
-                << theLinearVariation  << ", "
+                << theAnglesVariation  << ", "
                 << theHasRefPoint      << ", "
                 << "SMESH.PointStruct( "
                 << TVar( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
                 << TVar( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
                 << TVar( theHasRefPoint ? theRefPoint.z : 0 ) << " ), "
-                << theMakeGroups       << " )";
+                << theMakeGroups           << ", "
+                << TVar( theScaleFactors ) << ", "
+                << theScalesVariation      << " )";
   }
   else
   {
@@ -4033,6 +4066,7 @@ SMESH_MeshEditor_i::ScaleMakeMesh(SMESH::SMESH_IDSource_ptr  theObject,
 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)
@@ -4058,7 +4092,9 @@ SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::Offset( SMESH::SMESH_IDSource_ptr theO
       TPreviewMesh * tmpMesh = getPreviewMesh();
       tgtMesh = tmpMesh;
       tmpMesh->Copy( elements, copyElements );
+      elements.swap( copyElements );
       theCopyGroups = false;
+      theCopyElements = false;
     }
     else
     {
@@ -4067,26 +4103,40 @@ SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::Offset( SMESH::SMESH_IDSource_ptr theO
       SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
       tgtMesh = & mesh_i->GetImpl();
     }
-    groupIds = getEditor().Offset( elements, theValue, tgtMesh, theCopyGroups, !myIsPreviewMode );
+    groupIds = getEditor().Offset( elements, theValue, tgtMesh,
+                                   theCopyGroups, theCopyElements, !myIsPreviewMode );
 
     tgtMesh->GetMeshDS()->Modified();
   }
 
   if ( myIsPreviewMode )
   {
-    getPreviewMesh()->Remove( SMESHUtils::elemSetIterator( copyElements ));
+    //getPreviewMesh()->Remove( SMESHUtils::elemSetIterator( copyElements ));
   }
   else
   {
+    if ( *theMeshName && mesh_var->NbFaces() == 0 )
+    {
+      // 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);
+    }
+    if ( !groupIds ) // nothing changed in the current mesh
+      THROW_SALOME_CORBA_EXCEPTION("Offset failed", SALOME::INTERNAL_ERROR);
+
     theGroups = theCopyGroups ? getGroups( groupIds.get() ) : new SMESH::ListOfGroups;
 
     // 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( "
+    pyDump << theGroups << " = " << this << ".Offset( "
+           << theObject << ", "
            << theValue << ", "
            << theCopyGroups << ", "
+           << theCopyElements << ", "
            << "'" << theMeshName<< "')";
   }
 
@@ -4164,6 +4214,7 @@ FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr      theObject,
   initData();
 
   TIDSortedNodeSet nodes;
+  prepareIdSource( theObject );
   idSourceToNodeSet( theObject, getMeshDS(), nodes );
 
   findCoincidentNodes( nodes, Tolerance, GroupsOfNodes, SeparateCornersAndMedium );
@@ -4178,13 +4229,13 @@ FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr      theObject,
 
 //================================================================================
 /*!
- * \brief Finds nodes coinsident with Tolerance within Object excluding nodes within
+ * \brief Finds nodes coincident with Tolerance within Objects excluding nodes within
  *        ExceptSubMeshOrGroups
  */
 //================================================================================
 
 void SMESH_MeshEditor_i::
-FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr      theObject,
+FindCoincidentNodesOnPartBut(const SMESH::ListOfIDSources&  theObjects,
                              CORBA::Double                  theTolerance,
                              SMESH::array_of_long_array_out theGroupsOfNodes,
                              const SMESH::ListOfIDSources&  theExceptSubMeshOrGroups,
@@ -4195,19 +4246,22 @@ FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr      theObject,
   initData();
 
   TIDSortedNodeSet nodes;
-  idSourceToNodeSet( theObject, getMeshDS(), nodes );
-
+  for ( CORBA::ULong i = 0; i < theObjects.length(); ++i )
+  {
+    prepareIdSource( theObjects[i] );
+    idSourceToNodeSet( theObjects[i], getMeshDS(), nodes );
+  }
   for ( CORBA::ULong i = 0; i < theExceptSubMeshOrGroups.length(); ++i )
   {
-    SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( theExceptSubMeshOrGroups[i],
-                                                         SMESH::NODE );
-    while ( nodeIt->more() )
-      nodes.erase( cast2Node( nodeIt->next() ));
+    if ( SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( theExceptSubMeshOrGroups[i],
+                                                              SMESH::NODE ))
+      while ( nodeIt->more() )
+        nodes.erase( cast2Node( nodeIt->next() ));
   }
   findCoincidentNodes( nodes, theTolerance, theGroupsOfNodes, theSeparateCornersAndMedium );
 
   TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPartBut( "
-                << theObject<<", "
+                << theObject<<", "
                 << theTolerance << ", "
                 << theExceptSubMeshOrGroups << ", "
                 << theSeparateCornersAndMedium << " )";
@@ -4237,9 +4291,9 @@ void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfN
   for ( CORBA::ULong i = 0; i < NodesToKeep.length(); ++i )
   {
     prepareIdSource( NodesToKeep[i] );
-    SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( NodesToKeep[i], SMESH::NODE );
-    while ( nodeIt->more() )
-      setOfNodesToKeep.insert( setOfNodesToKeep.end(), cast2Node( nodeIt->next() ));
+    if ( SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( NodesToKeep[i], SMESH::NODE ))
+      while ( nodeIt->more() )
+        setOfNodesToKeep.insert( setOfNodesToKeep.end(), cast2Node( nodeIt->next() ));
   }
 
   ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
@@ -4280,30 +4334,47 @@ void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfN
 //purpose  :
 //=======================================================================
 
-void SMESH_MeshEditor_i::FindEqualElements(SMESH::SMESH_IDSource_ptr      theObject,
-                                           SMESH::array_of_long_array_out GroupsOfElementsID)
+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_TRY;
   initData();
 
-  SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow(theObject);
-  if ( !(!group->_is_nil() && group->GetType() == SMESH::NODE) )
+  theGroupsOfElementsID = new SMESH::array_of_long_array;
+
+  TIDSortedElemSet elems;
+  bool hasOkObject = false;
+  bool emptyIfIsMesh= ( theObjects.length() == 1 && theExceptObjects.length() == 0 );
+
+  for ( CORBA::ULong i = 0; i < theObjects.length(); ++i )
   {
-    TIDSortedElemSet elems;
-    idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true);
+    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 ( hasOkObject )
+  {
+    for ( CORBA::ULong i = 0; i < theExceptObjects.length(); ++i )
+    {
+      if ( SMDS_ElemIteratorPtr elemIt = myMesh_i->GetElements( theExceptObjects[i], SMESH::ALL ))
+        while ( elemIt->more() )
+          elems.erase( elemIt->next() );
+    }
 
     ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
     getEditor().FindEqualElements( elems, aListOfListOfElementsID );
 
-    GroupsOfElementsID = new SMESH::array_of_long_array;
-    GroupsOfElementsID->length( aListOfListOfElementsID.size() );
+    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 = (*GroupsOfElementsID)[ j ];
+      SMESH::long_array& aGroup = (*theGroupsOfElementsID)[ j ];
       list<int>&      listOfIDs = *arraysIt;
       aGroup.length( listOfIDs.size() );
       list<int>::iterator idIt = listOfIDs.begin();
@@ -4312,7 +4383,8 @@ void SMESH_MeshEditor_i::FindEqualElements(SMESH::SMESH_IDSource_ptr      theObj
     }
 
     TPythonDump() << "equal_elements = " << this << ".FindEqualElements( "
-                  <<theObject<<" )";
+                  << theObjects << ", "
+                  << theExceptObjects << " )";
   }
 
   SMESH_CATCH( SMESH::throwCorbaException );
@@ -4323,7 +4395,8 @@ void SMESH_MeshEditor_i::FindEqualElements(SMESH::SMESH_IDSource_ptr      theObj
 //purpose  :
 //=======================================================================
 
-void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& GroupsOfElementsID)
+void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& theGroupsOfElementsID,
+                                       const SMESH::ListOfIDSources&     theElementsToKeep)
   throw (SALOME::SALOME_Exception)
 {
   SMESH_TRY;
@@ -4332,15 +4405,31 @@ void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& GroupsO
   TPythonDump aTPythonDump;
   aTPythonDump << this << ".MergeElements( [";
 
+  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 ]);
+  }
+
   ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
 
-  for ( CORBA::ULong i = 0; i < GroupsOfElementsID.length(); i++ ) {
-    const SMESH::long_array& anElemsIDGroup = GroupsOfElementsID[ i ];
+  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++ ) {
+    for ( CORBA::ULong j = 0; j < anElemsIDGroup.length(); j++ )
+    {
       CORBA::Long id = anElemsIDGroup[ j ];
-      aListOfElemsID.push_back( id );
+      if ( idsToKeep.Contains( id )) aListOfElemsID.push_front( id );
+      else                           aListOfElemsID.push_back( id );
     }
     if ( aListOfElemsID.size() < 2 )
       aListOfListOfElementsID.pop_back();
@@ -4352,7 +4441,7 @@ void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& GroupsO
 
   declareMeshModified( /*isReComputeSafe=*/true );
 
-  aTPythonDump << "] )";
+  aTPythonDump << "], " << theElementsToKeep << " )";
 
   SMESH_CATCH( SMESH::throwCorbaException );
 }
@@ -4590,6 +4679,7 @@ SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementID
   SMESH_TRY;
   SMESH::long_array_var res = new SMESH::long_array;
 
+  prepareIdSource( elementIDs );
   if ( type != SMESH::NODE )
   {
     SMESH::array_of_ElementType_var types = elementIDs->GetTypes();
@@ -4598,6 +4688,16 @@ SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementID
          type != types[0] ) // but search of elements of dim > 0
       return res._retn();
   }
+
+  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 );
+  }
+
   if ( SMESH::DownCast<SMESH_Mesh_i*>( elementIDs )) // elementIDs is the whole mesh 
     return FindElementsByPoint( x,y,z, type );
 
@@ -4607,18 +4707,15 @@ SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementID
   if ( !theElementSearcher )
   {
     // 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,
-                         ( type == SMESH::NODE ? SMDSAbs_All : (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 = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemsIt );
+    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 );
   }
 
   vector< const SMDS_MeshElement* > foundElems;
@@ -4636,6 +4733,72 @@ SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementID
   return 0;
 }
 
+//=======================================================================
+//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 []
+//=======================================================================
+
+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)
+{
+  if ( CORBA::is_nil( meshObject ))
+    THROW_SALOME_CORBA_EXCEPTION("NULL meshObject", SALOME::BAD_PARAM);
+
+  SMESH_TRY;
+
+  SMESH::SMESH_Mesh_var mesh = meshObject->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->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 ))
+    {
+      prepareIdSource( meshObject );
+      elemIt = myMesh_i->GetElements( meshObject, type );
+      if ( !elemIt )
+        return -1;
+    }
+    theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemIt );
+  }
+
+  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();
+  }
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return -1;
+}
+
 //=======================================================================
 //function : GetPointState
 //purpose  : Return point state in a closed 2D mesh in terms of TopAbs_State enumeration.
@@ -4701,6 +4864,111 @@ CORBA::Boolean SMESH_MeshEditor_i::IsCoherentOrientation2D()
   return isGoodOri;
 }
 
+//=======================================================================
+//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.
+//=======================================================================
+
+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)
+{
+  if ( CORBA::is_nil( theEdges ))
+    THROW_SALOME_CORBA_EXCEPTION("Get1DBranches(): NULL group given", SALOME::BAD_PARAM);
+
+  SMESH::array_of_long_array_var edgeGroupArray = new SMESH::array_of_long_array;
+  theNodeGroups = new SMESH::array_of_long_array;
+
+  SMESH_TRY;
+
+  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();
+}
+
+//=======================================================================
+//function : FindSharpEdges
+//purpose  : Return sharp edges of faces and non-manifold ones. Optionally add existing edges.
+//=======================================================================
+
+SMESH::ListOfEdges* SMESH_MeshEditor_i::FindSharpEdges(CORBA::Double  theAngle,
+                                                       CORBA::Boolean theAddExisting)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH::ListOfEdges_var resultEdges = new SMESH::ListOfEdges;
+  SMESH_TRY;
+
+  initData();
+
+  std::vector< SMESH_MeshAlgos::Edge > edges =
+    SMESH_MeshAlgos::FindSharpEdges( getMeshDS(), theAngle, theAddExisting );
+
+  if ( myIsPreviewMode ) // fill a preview mesh with edges
+  {
+    TPreviewMesh* mesh = getPreviewMesh( SMDSAbs_Edge );
+    SMDS_Mesh*  meshDS = mesh->GetMeshDS();
+    for ( size_t i = 0; i < edges.size(); ++i )
+    {
+      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 );
+      }
+    }
+  }
+  else
+  {
+    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;
+    }
+  }
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return resultEdges._retn();
+}
+
 //=======================================================================
 //function : FindFreeBorders
 //purpose  : Returns all or only closed FreeBorder's.
@@ -4735,7 +5003,9 @@ SMESH::ListOfFreeBorders* SMESH_MeshEditor_i::FindFreeBorders(CORBA::Boolean clo
 //purpose  : Fill with 2D elements a hole defined by a FreeBorder.
 //=======================================================================
 
-void SMESH_MeshEditor_i::FillHole(const SMESH::FreeBorder& theHole)
+SMESH::SMESH_Group_ptr 
+SMESH_MeshEditor_i::FillHole(const SMESH::FreeBorder& theHole,
+                             const char*              theGroupName)
   throw (SALOME::SALOME_Exception)
 {
   initData();
@@ -4758,6 +5028,7 @@ void SMESH_MeshEditor_i::FillHole(const SMESH::FreeBorder& theHole)
 
   SMESH_TRY;
 
+  // prepare a preview mesh
   MeshEditor_I::TPreviewMesh* previewMesh = 0;
   SMDS_Mesh* meshDS = getMeshDS();
   if ( myIsPreviewMode )
@@ -4780,26 +5051,66 @@ void SMESH_MeshEditor_i::FillHole(const SMESH::FreeBorder& theHole)
     meshDS = previewMesh->GetMeshDS();
   }
 
+  // fill the hole
   std::vector<const SMDS_MeshElement*> newFaces;
   SMESH_MeshAlgos::FillHole( bordNodes, *meshDS, newFaces );
 
   if ( myIsPreviewMode )
   {
+    // 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 );
+
+      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() << this << ".FillHole( SMESH.FreeBorder(" << theHole.nodeIDs << " ))";
+    TPythonDump pyDump;
+    if ( group->_is_nil() ) pyDump << "_group = ";
+    else                    pyDump << group << " = ";
+    pyDump << this << ".FillHole( SMESH.FreeBorder(" << theHole.nodeIDs << " ))";
+
+    return group._retn();
   }
 
   SMESH_CATCH( SMESH::throwCorbaException );
+
+  return SMESH::SMESH_Group::_nil();
 }
 
 //=======================================================================
@@ -5308,23 +5619,20 @@ CORBA::Boolean SMESH_MeshEditor_i::ChangeElemNodes(CORBA::Long ide,
   initData();
 
   const SMDS_MeshElement* elem = getMeshDS()->FindElement(ide);
-  if(!elem) return false;
+  if ( !elem ) return false;
 
   int nbn = newIDs.length();
-  int i=0;
   vector<const SMDS_MeshNode*> aNodes(nbn);
-  int nbn1=-1;
-  for(; i<nbn; i++) {
-    const SMDS_MeshNode* aNode = getMeshDS()->FindNode(newIDs[i]);
-    if(aNode) {
-      nbn1++;
-      aNodes[nbn1] = aNode;
-    }
+  for ( int i = 0; i < nbn; i++ ) {
+    const SMDS_MeshNode* aNode = getMeshDS()->FindNode( newIDs[ i ]);
+    if ( !aNode )
+      return false;
+    aNodes[ i ] = aNode;
   }
   TPythonDump() << "isDone = " << this << ".ChangeElemNodes( "
                 << ide << ", " << newIDs << " )";
 
-  bool res = getMeshDS()->ChangeElementNodes( elem, & aNodes[0], nbn1+1 );
+  bool res = getMeshDS()->ChangeElementNodes( elem, & aNodes[0], aNodes.size() );
 
   declareMeshModified( /*isReComputeSafe=*/ !res );
 
@@ -5352,8 +5660,8 @@ void SMESH_MeshEditor_i::convertToQuadratic(CORBA::Boolean            theForce3d
   bool elemsOK;
   if ( !( elemsOK = CORBA::is_nil( theObject )))
   {
-    elemsOK =  idSourceToSet( theObject, getMeshDS(), elems,
-                              SMDSAbs_All, /*emptyIfIsMesh=*/true );
+    elemsOK = idSourceToSet( theObject, getMeshDS(), elems,
+                             SMDSAbs_All, /*emptyIfIsMesh=*/true );
   }
   if ( elemsOK )
   {
@@ -5475,8 +5783,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();
-  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");
 
@@ -5504,7 +5811,7 @@ void SMESH_MeshEditor_i::dumpGroupsList(TPythonDump &               theDumpPytho
 */
 //================================================================================
 
-std::string SMESH_MeshEditor_i::generateGroupName(const std::string& thePrefix)
+std::string SMESH_MeshEditor_i::GenerateGroupName(const std::string& thePrefix)
 {
   SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
   set<std::string> groupNames;
@@ -5566,10 +5873,21 @@ bool SMESH_MeshEditor_i::idSourceToSet(SMESH::SMESH_IDSource_ptr  theIDSource,
   }
   if ( emptyIfIsMesh && SMESH::DownCast<SMESH_Mesh_i*>( theIDSource ))
   {
-    if ( error && getMeshDS()->GetMeshInfo().NbElements( theType ) == 0 )
+    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 )
@@ -5658,7 +5976,7 @@ SMESH_MeshEditor_i::DoubleElements(SMESH::SMESH_IDSource_ptr theElements,
       {
         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++ )
+        for ( size_t i = 0; i < aSeq.size(); i++ )
           groupDS->SMDSGroup().Add( aSeq[i] );
       }
     }
@@ -5826,7 +6144,7 @@ SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
     SMESH::long_array_var anIds = GetLastCreatedNodes();
     if (anIds->length() > 0) {
       std::string anUnindexedName (theNodes->GetName());
-      std::string aNewName = generateGroupName(anUnindexedName + "_double");
+      std::string aNewName = GenerateGroupName(anUnindexedName + "_double");
       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
       aNewGroup->Add(anIds);
       pyDump << aNewGroup << " = ";
@@ -5925,7 +6243,7 @@ SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
     SMESH::long_array_var anIds = GetLastCreatedNodes();
     if (anIds->length() > 0) {
       std::string anUnindexedName (theNodes[0]->GetName());
-      std::string aNewName = generateGroupName(anUnindexedName + "_double");
+      std::string aNewName = GenerateGroupName(anUnindexedName + "_double");
       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
       aNewGroup->Add(anIds);
       pyDump << aNewGroup << " = ";
@@ -6149,7 +6467,7 @@ SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
   {
     // Create group with newly created elements
     CORBA::String_var elemGroupName = theElems->GetName();
-    std::string aNewName = generateGroupName( std::string(elemGroupName.in()) + "_double");
+    std::string aNewName = GenerateGroupName( std::string(elemGroupName.in()) + "_double");
     if ( !getEditor().GetLastCreatedElems().empty() && theElemGroupNeeded )
     {
       SMESH::long_array_var anIds = GetLastCreatedElems();
@@ -6381,7 +6699,7 @@ SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems
   {
     // Create group with newly created elements
     CORBA::String_var elemGroupName = theElems[0]->GetName();
-    std::string aNewName = generateGroupName( std::string(elemGroupName.in()) + "_double");
+    std::string aNewName = GenerateGroupName( std::string(elemGroupName.in()) + "_double");
     if ( !getEditor().GetLastCreatedElems().empty() && theElemGroupNeeded )
     {
       SMESH::long_array_var anIds = GetLastCreatedElems();
@@ -6537,7 +6855,7 @@ SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theEl
     if ( ivol > 0 )
     {
       aNewVolumeGroup = myMesh_i->CreateGroup(SMESH::VOLUME,
-                                              generateGroupName("affectedVolumes").c_str());
+                                              GenerateGroupName("affectedVolumes").c_str());
       aNewVolumeGroup->Add(volumeIds);
       aListOfGroups->length( nbGroups+1 );
       aListOfGroups[ nbGroups++ ] = aNewVolumeGroup._retn();
@@ -6545,7 +6863,7 @@ SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theEl
     if ( iface > 0 )
     {
       aNewFaceGroup = myMesh_i->CreateGroup(SMESH::FACE,
-                                            generateGroupName("affectedFaces").c_str());
+                                            GenerateGroupName("affectedFaces").c_str());
       aNewFaceGroup->Add(faceIds);
       aListOfGroups->length( nbGroups+1 );
       aListOfGroups[ nbGroups++ ] = aNewFaceGroup._retn();
@@ -6553,7 +6871,7 @@ SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theEl
     if ( iedge > 0 )
     {
       aNewEdgeGroup = myMesh_i->CreateGroup(SMESH::EDGE,
-                                            generateGroupName("affectedEdges").c_str());
+                                            GenerateGroupName("affectedEdges").c_str());
       aNewEdgeGroup->Add(edgeIds);
       aListOfGroups->length( nbGroups+1 );
       aListOfGroups[ nbGroups++ ] = aNewEdgeGroup._retn();
@@ -6915,7 +7233,7 @@ CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
   for ( CORBA::ULong i = 0; i < groups.length(); ++i )
   {
     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];
@@ -6963,7 +7281,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;
-  if ( strlen(groupName) )
+  if ( strlen( groupName ))
   {
     SMESH::ElementType groupType = SMESH::ElementType( int(elemType)-1 );
     group_var = mesh_i->CreateGroup( groupType, groupName );
@@ -7075,16 +7393,16 @@ void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments,
   }
   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() );
-      }
-    }
+    // 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 );
@@ -7095,24 +7413,24 @@ void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments,
   }
 
   // convert input polySegments
-  ::SMESH_MeshEditor::TListOfPolySegments segments( theSegments.length() );
+  SMESH_MeshAlgos::TListOfPolySegments segments( theSegments.length() );
   for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
   {
-    SMESH::PolySegment&               segIn = theSegments[ i ];
-    ::SMESH_MeshEditor::PolySegment& segOut = segments[ 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 );
-    if ( !segOut.myNode1[0] )
-      THROW_SALOME_CORBA_EXCEPTION( SMESH_Comment( "Invalid node ID: ") << segIn.node1ID1,
-                                    SALOME::BAD_PARAM );
-    if ( !segOut.myNode1[1] )
-      THROW_SALOME_CORBA_EXCEPTION( SMESH_Comment( "Invalid node ID: ") << segIn.node2ID1,
-                                    SALOME::BAD_PARAM );
   }
 
   // get a static ElementSearcher
@@ -7122,15 +7440,24 @@ void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments,
     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
 
   // compute
-  getEditor().MakePolyLine( segments, groupDS, theElementSearcher );
+  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_MeshEditor::PolySegment& segIn = segments[ 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();
@@ -7158,3 +7485,58 @@ void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments,
   SMESH_CATCH( SMESH::throwCorbaException );
   return;
 }
+
+//================================================================================
+/*!
+ * \brief Create a slot of given width around given 1D elements lying on a triangle mesh.
+ *        The slot is constructed 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();
+
+  // get standalone face groups to be updated
+  std::vector< SMDS_MeshGroup* > faceGroups;
+  const std::set<SMESHDS_GroupBase*>& allGroups = meshDS->GetGroups();
+  std::set<SMESHDS_GroupBase*>::const_iterator grIt = allGroups.begin();
+  for ( ; grIt != allGroups.end(); ++grIt )
+    if ( const SMESHDS_Group* gr = dynamic_cast< const SMESHDS_Group* >( *grIt ))
+      if ( gr->GetType() == SMDSAbs_Face )
+        faceGroups.push_back( & const_cast< SMESHDS_Group* >( gr )->SMDSGroup() );
+
+  std::vector< SMESH_MeshAlgos::Edge > edges =
+    SMESH_MeshAlgos::MakeSlot( SMESH_Mesh_i::GetElements( theSegments, SMESH::EDGE ),
+                               theWidth, meshDS, faceGroups );
+
+  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();
+}