Salome HOME
Merge eap/23491 branch.
authorrnv <rnv@opencascade.com>
Mon, 15 Jan 2018 12:48:20 +0000 (15:48 +0300)
committerrnv <rnv@opencascade.com>
Mon, 15 Jan 2018 12:48:20 +0000 (15:48 +0300)
1  2 
src/SMESH/SMESH_MeshEditor.cxx
src/SMESHGUI/SMESH_msg_en.ts
src/SMESHUtils/SMESH_MeshAlgos.hxx
src/SMESH_I/SMESH_2smeshpy.cxx
src/SMESH_I/SMESH_MeshEditor_i.cxx

index e414cd9725b22bf662e17c083ec89152e5c87316,62bb61a72d52fdbc4ca3bd94ae492be898dfa039..b11f6c32adc78541bcf1e5eeb10638a17f6b0974
  #include <sstream>
  
  #include <boost/tuple/tuple.hpp>
+ #include <boost/container/flat_set.hpp>
  
  #include <Standard_Failure.hxx>
  #include <Standard_ErrorHandler.hxx>
 +#include <OSD_Parallel.hxx>
 +
 +#include "SMESH_TryCatch.hxx" // include after OCCT headers!
  
  #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
  
@@@ -1279,7 -1277,7 +1280,7 @@@ int SMESH_MeshEditor::Reorient2D (TIDSo
          }
          if ( otherFace && otherFace != theFace)
          {
 -          // link must be reverse in otherFace if orientation ot otherFace
 +          // link must be reverse in otherFace if orientation to otherFace
            // is same as that of theFace
            if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
            {
@@@ -1501,7 -1499,7 +1502,7 @@@ bool SMESH_MeshEditor::QuadToTri (TIDSo
  //=======================================================================
  /*!
   * \brief Split each of given quadrangles into 4 triangles.
 - * \param theElems - The faces to be splitted. If empty all faces are split.
 + * \param theElems - The faces to be split. If empty all faces are split.
   */
  //=======================================================================
  
@@@ -4570,11 -4568,7 +4571,7 @@@ void SMESH_MeshEditor::sweepElement(con
          std::swap( itNN[0],    itNN[1] );
          std::swap( prevNod[0], prevNod[1] );
          std::swap( nextNod[0], nextNod[1] );
- #if defined(__APPLE__)
          std::swap( isSingleNode[0], isSingleNode[1] );
- #else
-         isSingleNode.swap( isSingleNode[0], isSingleNode[1] );
- #endif
          if ( nbSame > 0 )
            sames[0] = 1 - sames[0];
          iNotSameNode = 1 - iNotSameNode;
@@@ -6145,7 -6139,7 +6142,7 @@@ SMESH_MeshEditor::ExtrusionAlongTrack (
          makeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
          LLPPs.push_back(LPP);
          UsedNums.Add(k);
 -        // update startN for search following egde
 +        // update startN for search following edge
          if( aN1->GetID() == startNid ) startNid = aN2->GetID();
          else startNid = aN1->GetID();
          break;
@@@ -6444,7 -6438,7 +6441,7 @@@ SMESH_MeshEditor::ExtrusionAlongTrack (
          makeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
          LLPPs.push_back(LPP);
          UsedNums.Add(k);
 -        // update startN for search following egde
 +        // update startN for search following edge
          if ( aN1isOK ) aVprev = aV2;
          else           aVprev = aV1;
          break;
@@@ -10599,6 -10593,559 +10596,559 @@@ SMESH_MeshEditor::FindMatchingNodes(set
    return SEW_OK;
  }
  
+ namespace // automatically find theAffectedElems for DoubleNodes()
+ {
+   bool isOut( const SMDS_MeshNode* n, const gp_XYZ& norm, const SMDS_MeshElement* elem );
+   //--------------------------------------------------------------------------------
+   // Nodes shared by adjacent FissureBorder's.
+   // 1 node  if FissureBorder separates faces
+   // 2 nodes if FissureBorder separates volumes
+   struct SubBorder
+   {
+     const SMDS_MeshNode* _nodes[2];
+     int                  _nbNodes;
+     SubBorder( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2 = 0 )
+     {
+       _nodes[0] = n1;
+       _nodes[1] = n2;
+       _nbNodes = bool( n1 ) + bool( n2 );
+       if ( _nbNodes == 2 && n1 > n2 )
+         std::swap( _nodes[0], _nodes[1] );
+     }
+     bool operator<( const SubBorder& other ) const
+     {
+       for ( int i = 0; i < _nbNodes; ++i )
+       {
+         if ( _nodes[i] < other._nodes[i] ) return true;
+         if ( _nodes[i] > other._nodes[i] ) return false;
+       }
+       return false;
+     }
+   };
+   //--------------------------------------------------------------------------------
+   // Map a SubBorder to all FissureBorder it bounds
+   struct FissureBorder;
+   typedef std::map< SubBorder, std::vector< FissureBorder* > > TBorderLinks;
+   typedef TBorderLinks::iterator                               TMappedSub;
+   //--------------------------------------------------------------------------------
+   /*!
+    * \brief Element border (volume facet or face edge) at a fissure
+    */
+   struct FissureBorder
+   {
+     std::vector< const SMDS_MeshNode* > _nodes;    // border nodes
+     const SMDS_MeshElement*             _elems[2]; // volume or face adjacent to fissure
+     std::vector< TMappedSub           > _mappedSubs;  // Sub() in TBorderLinks map
+     std::vector< const SMDS_MeshNode* > _sortedNodes; // to compare FissureBorder's
+     FissureBorder( FissureBorder && from ) // move constructor
+     {
+       std::swap( _nodes,       from._nodes );
+       std::swap( _sortedNodes, from._sortedNodes );
+       _elems[0] = from._elems[0];
+       _elems[1] = from._elems[1];
+     }
+     FissureBorder( const SMDS_MeshElement*                  elemToDuplicate,
+                    std::vector< const SMDS_MeshElement* > & adjElems)
+       : _nodes( elemToDuplicate->NbCornerNodes() )
+     {
+       for ( size_t i = 0; i < _nodes.size(); ++i )
+         _nodes[i] = elemToDuplicate->GetNode( i );
+       SMDSAbs_ElementType type = SMDSAbs_ElementType( elemToDuplicate->GetType() + 1 );
+       findAdjacent( type, adjElems );
+     }
+     FissureBorder( const SMDS_MeshNode**                    nodes,
+                    const size_t                             nbNodes,
+                    const SMDSAbs_ElementType                adjElemsType,
+                    std::vector< const SMDS_MeshElement* > & adjElems)
+       : _nodes( nodes, nodes + nbNodes )
+     {
+       findAdjacent( adjElemsType, adjElems );
+     }
+     void findAdjacent( const SMDSAbs_ElementType                adjElemsType,
+                        std::vector< const SMDS_MeshElement* > & adjElems)
+     {
+       _elems[0] = _elems[1] = 0;
+       adjElems.clear();
+       if ( SMDS_Mesh::GetElementsByNodes( _nodes, adjElems, adjElemsType ))
+         for ( size_t i = 0; i < adjElems.size() && i < 2; ++i )
+           _elems[i] = adjElems[i];
+     }
+     bool operator<( const FissureBorder& other ) const
+     {
+       return GetSortedNodes() < other.GetSortedNodes();
+     }
+     const std::vector< const SMDS_MeshNode* >& GetSortedNodes() const
+     {
+       if ( _sortedNodes.empty() && !_nodes.empty() )
+       {
+         FissureBorder* me = const_cast<FissureBorder*>( this );
+         me->_sortedNodes = me->_nodes;
+         std::sort( me->_sortedNodes.begin(), me->_sortedNodes.end() );
+       }
+       return _sortedNodes;
+     }
+     size_t NbSub() const
+     {
+       return _nodes.size();
+     }
+     SubBorder Sub(size_t i) const
+     {
+       return SubBorder( _nodes[i], NbSub() > 2 ? _nodes[ (i+1)%NbSub() ] : 0 );
+     }
+     void AddSelfTo( TBorderLinks& borderLinks )
+     {
+       _mappedSubs.resize( NbSub() );
+       for ( size_t i = 0; i < NbSub(); ++i )
+       {
+         TBorderLinks::iterator s2b =
+           borderLinks.insert( std::make_pair( Sub(i), TBorderLinks::mapped_type() )).first;
+         s2b->second.push_back( this );
+         _mappedSubs[ i ] = s2b;
+       }
+     }
+     void Clear()
+     {
+       _nodes.clear();
+     }
+     const SMDS_MeshElement* GetMarkedElem() const
+     {
+       if ( _nodes.empty() ) return 0; // cleared
+       if ( _elems[0] && _elems[0]->isMarked() ) return _elems[0];
+       if ( _elems[1] && _elems[1]->isMarked() ) return _elems[1];
+       return 0;
+     }
+     gp_XYZ GetNorm() const // normal to the border
+     {
+       gp_XYZ norm;
+       if ( _nodes.size() == 2 )
+       {
+         gp_XYZ avgNorm( 0,0,0 ); // sum of normals of adjacent faces
+         if ( SMESH_MeshAlgos::FaceNormal( _elems[0], norm ))
+           avgNorm += norm;
+         if ( SMESH_MeshAlgos::FaceNormal( _elems[1], norm ))
+           avgNorm += norm;
+         gp_XYZ bordDir( SMESH_NodeXYZ( _nodes[0] ) - SMESH_NodeXYZ( _nodes[1] ));
+         norm = bordDir ^ avgNorm;
+       }
+       else
+       {
+         SMESH_NodeXYZ p0( _nodes[0] );
+         SMESH_NodeXYZ p1( _nodes[1] );
+         SMESH_NodeXYZ p2( _nodes[2] );
+         norm = ( p0 - p1 ) ^ ( p2 - p1 );
+       }
+       if ( isOut( _nodes[0], norm, GetMarkedElem() ))
+         norm.Reverse();
+       return norm;
+     }
+     void ChooseSide() // mark an _elem located at positive side of fissure
+     {
+       _elems[0]->setIsMarked( true );
+       gp_XYZ norm = GetNorm();
+       double maxX = norm.Coord(1);
+       if ( Abs( maxX ) < Abs( norm.Coord(2)) ) maxX = norm.Coord(2);
+       if ( Abs( maxX ) < Abs( norm.Coord(3)) ) maxX = norm.Coord(3);
+       if ( maxX < 0 )
+       {
+         _elems[0]->setIsMarked( false );
+         _elems[1]->setIsMarked( true );
+       }
+     }
+   }; // struct FissureBorder
+   //--------------------------------------------------------------------------------
+   /*!
+    * \brief Classifier of elements at fissure edge
+    */
+   class FissureNormal
+   {
+     std::vector< gp_XYZ > _normals;
+     bool                  _bothIn;
+   public:
+     void Add( const SMDS_MeshNode* n, const FissureBorder& bord )
+     {
+       _bothIn = false;
+       _normals.reserve(2);
+       _normals.push_back( bord.GetNorm() );
+       if ( _normals.size() == 2 )
+         _bothIn = !isOut( n, _normals[0], bord.GetMarkedElem() );
+     }
+     bool IsIn( const SMDS_MeshNode* n, const SMDS_MeshElement* elem ) const
+     {
+       bool isIn = false;
+       switch ( _normals.size() ) {
+       case 1:
+       {
+         isIn = !isOut( n, _normals[0], elem );
+         break;
+       }
+       case 2:
+       {
+         bool in1 = !isOut( n, _normals[0], elem );
+         bool in2 = !isOut( n, _normals[1], elem );
+         isIn = _bothIn ? ( in1 && in2 ) : ( in1 || in2 );
+       }
+       }
+       return isIn;
+     }
+   };
+   //================================================================================
+   /*!
+    * \brief Classify an element by a plane passing through a node
+    */
+   //================================================================================
+   bool isOut( const SMDS_MeshNode* n, const gp_XYZ& norm, const SMDS_MeshElement* elem )
+   {
+     SMESH_NodeXYZ p = n;
+     double sumDot = 0;
+     for ( int i = 0, nb = elem->NbCornerNodes(); i < nb; ++i )
+     {
+       SMESH_NodeXYZ pi = elem->GetNode( i );
+       sumDot += norm * ( pi - p );
+     }
+     return sumDot < -1e-100;
+   }
+   //================================================================================
+   /*!
+    * \brief Find FissureBorder's by nodes to duplicate
+    */
+   //================================================================================
+   void findFissureBorders( const TIDSortedElemSet&        theNodes,
+                            std::vector< FissureBorder > & theFissureBorders )
+   {
+     TIDSortedElemSet::const_iterator nIt = theNodes.begin();
+     const SMDS_MeshNode* n = dynamic_cast< const SMDS_MeshNode*>( *nIt );
+     if ( !n ) return;
+     SMDSAbs_ElementType elemType = SMDSAbs_Volume;
+     if ( n->NbInverseElements( elemType ) == 0 )
+     {
+       elemType = SMDSAbs_Face;
+       if ( n->NbInverseElements( elemType ) == 0 )
+         return;
+     }
+     // unmark elements touching the fissure
+     for ( ; nIt != theNodes.end(); ++nIt )
+       SMESH_MeshAlgos::MarkElems( cast2Node(*nIt)->GetInverseElementIterator(), false );
+     // loop on elements touching the fissure to get their borders belonging to the fissure
+     std::set< FissureBorder >              fissureBorders;
+     std::vector< const SMDS_MeshElement* > adjElems;
+     std::vector< const SMDS_MeshNode* >    nodes;
+     SMDS_VolumeTool volTool;
+     for ( nIt = theNodes.begin(); nIt != theNodes.end(); ++nIt )
+     {
+       SMDS_ElemIteratorPtr invIt = cast2Node(*nIt)->GetInverseElementIterator( elemType );
+       while ( invIt->more() )
+       {
+         const SMDS_MeshElement* eInv = invIt->next();
+         if ( eInv->isMarked() ) continue;
+         eInv->setIsMarked( true );
+         if ( elemType == SMDSAbs_Volume )
+         {
+           volTool.Set( eInv );
+           int iQuad = eInv->IsQuadratic() ? 2 : 1;
+           for ( int iF = 0, nbF = volTool.NbFaces(); iF < nbF; ++iF )
+           {
+             const SMDS_MeshNode** nn = volTool.GetFaceNodes( iF );
+             int                  nbN = volTool.NbFaceNodes( iF ) / iQuad;
+             nodes.clear();
+             bool allOnFissure = true;
+             for ( int iN = 0; iN < nbN  && allOnFissure; iN += iQuad )
+               if (( allOnFissure = theNodes.count( nn[ iN ])))
+                 nodes.push_back( nn[ iN ]);
+             if ( allOnFissure )
+               fissureBorders.insert( std::move( FissureBorder( &nodes[0], nodes.size(),
+                                                                elemType, adjElems )));
+           }
+         }
+         else // elemType == SMDSAbs_Face
+         {
+           const SMDS_MeshNode* nn[2] = { eInv->GetNode( eInv->NbCornerNodes()-1 ), 0 };
+           bool            onFissure0 = theNodes.count( nn[0] ), onFissure1;
+           for ( int iN = 0, nbN = eInv->NbCornerNodes(); iN < nbN; ++iN )
+           {
+             nn[1]      = eInv->GetNode( iN );
+             onFissure1 = theNodes.count( nn[1] );
+             if ( onFissure0 && onFissure1 )
+               fissureBorders.insert( std::move( FissureBorder( nn, 2, elemType, adjElems )));
+             nn[0]      = nn[1];
+             onFissure0 = onFissure1;
+           }
+         }
+       }
+     }
+     theFissureBorders.reserve( theFissureBorders.size() + fissureBorders.size());
+     std::set< FissureBorder >::iterator bord = fissureBorders.begin();
+     for ( ; bord != fissureBorders.end(); ++bord )
+     {
+       theFissureBorders.push_back( std::move( const_cast<FissureBorder&>( *bord ) ));
+     }
+     return;
+   } // findFissureBorders()
+   //================================================================================
+   /*!
+    * \brief Find elements on one side of a fissure defined by elements or nodes to duplicate
+    *  \param [in] theElemsOrNodes - elements or nodes to duplicate
+    *  \param [in] theNodesNot - nodes not to duplicate
+    *  \param [out] theAffectedElems - the found elements
+    */
+   //================================================================================
+   void findAffectedElems( const TIDSortedElemSet& theElemsOrNodes,
+                           TIDSortedElemSet&       theAffectedElems)
+   {
+     if ( theElemsOrNodes.empty() ) return;
+     // find FissureBorder's
+     std::vector< FissureBorder >           fissure;
+     std::vector< const SMDS_MeshElement* > elemsByFacet;
+     TIDSortedElemSet::const_iterator elIt = theElemsOrNodes.begin();
+     if ( (*elIt)->GetType() == SMDSAbs_Node )
+     {
+       findFissureBorders( theElemsOrNodes, fissure );
+     }
+     else
+     {
+       fissure.reserve( theElemsOrNodes.size() );
+       for ( ; elIt != theElemsOrNodes.end(); ++elIt )
+         fissure.push_back( std::move( FissureBorder( *elIt, elemsByFacet )));
+     }
+     if ( fissure.empty() )
+       return;
+     // fill borderLinks
+     TBorderLinks borderLinks;
+     for ( size_t i = 0; i < fissure.size(); ++i )
+     {
+       fissure[i].AddSelfTo( borderLinks );
+     }
+     // get theAffectedElems
+     // unmark elements having nodes on the fissure, theAffectedElems elements will be marked
+     for ( size_t i = 0; i < fissure.size(); ++i )
+       for ( size_t j = 0; j < fissure[i]._nodes.size(); ++j )
+       {
+         SMESH_MeshAlgos::MarkElemNodes( fissure[i]._nodes[j]->GetInverseElementIterator(),
+                                         false, /*markElem=*/true );
+       }
+     std::vector<const SMDS_MeshNode *>                 facetNodes;
+     std::map< const SMDS_MeshNode*, FissureNormal >    fissEdgeNodes2Norm;
+     boost::container::flat_set< const SMDS_MeshNode* > fissureNodes;
+     // choose a side of fissure
+     fissure[0].ChooseSide();
+     theAffectedElems.insert( fissure[0].GetMarkedElem() );
+     size_t nbCheckedBorders = 0;
+     while ( nbCheckedBorders < fissure.size() )
+     {
+       // find a FissureBorder to treat
+       FissureBorder* bord = 0;
+       for ( size_t i = 0; i < fissure.size()  && !bord; ++i )
+         if ( fissure[i].GetMarkedElem() )
+           bord = & fissure[i];
+       for ( size_t i = 0; i < fissure.size()  && !bord; ++i )
+         if ( fissure[i].NbSub() > 0 && fissure[i]._elems[0] )
+         {
+           bord = & fissure[i];
+           bord->ChooseSide();
+           theAffectedElems.insert( bord->GetMarkedElem() );
+         }
+       if ( !bord ) return;
+       ++nbCheckedBorders;
+       // treat FissureBorder's linked to bord
+       fissureNodes.clear();
+       fissureNodes.insert( bord->_nodes.begin(), bord->_nodes.end() );
+       for ( size_t i = 0; i < bord->NbSub(); ++i )
+       {
+         TBorderLinks::iterator l2b = bord->_mappedSubs[ i ];
+         if ( l2b == borderLinks.end() || l2b->second.empty() ) continue;
+         std::vector< FissureBorder* >& linkedBorders = l2b->second;
+         const SubBorder&                          sb = l2b->first;
+         const SMDS_MeshElement*             bordElem = bord->GetMarkedElem();
+         if ( linkedBorders.size() == 1 ) // fissure edge reached, fill fissEdgeNodes2Norm
+         {
+           for ( int j = 0; j < sb._nbNodes; ++j )
+             fissEdgeNodes2Norm[ sb._nodes[j] ].Add( sb._nodes[j], *bord );
+           continue;
+         }
+         // add to theAffectedElems elems sharing nodes of a SubBorder and a node of bordElem
+         // until an elem adjacent to a neighbour FissureBorder is found
+         facetNodes.clear();
+         facetNodes.insert( facetNodes.end(), sb._nodes, sb._nodes + sb._nbNodes );
+         facetNodes.resize( sb._nbNodes + 1 );
+         while ( bordElem )
+         {
+           // check if bordElem is adjacent to a neighbour FissureBorder
+           for ( size_t j = 0; j < linkedBorders.size(); ++j )
+           {
+             FissureBorder* bord2 = linkedBorders[j];
+             if ( bord2 == bord ) continue;
+             if ( bordElem == bord2->_elems[0] || bordElem == bord2->_elems[1] )
+               bordElem = 0;
+             else
+               fissureNodes.insert( bord2->_nodes.begin(), bord2->_nodes.end() );
+           }
+           if ( !bordElem )
+             break;
+           // find the next bordElem
+           const SMDS_MeshElement* nextBordElem = 0;
+           for ( int iN = 0, nbN = bordElem->NbCornerNodes(); iN < nbN  && !nextBordElem; ++iN )
+           {
+             const SMDS_MeshNode* n = bordElem->GetNode( iN );
+             if ( fissureNodes.count( n )) continue;
+             facetNodes[ sb._nbNodes ] = n;
+             elemsByFacet.clear();
+             if ( SMDS_Mesh::GetElementsByNodes( facetNodes, elemsByFacet ) > 1 )
+             {
+               for ( size_t iE = 0; iE < elemsByFacet.size(); ++iE )
+                 if ( elemsByFacet[ iE ] != bordElem &&
+                      !elemsByFacet[ iE ]->isMarked() )
+                 {
+                   theAffectedElems.insert( elemsByFacet[ iE ]);
+                   elemsByFacet[ iE ]->setIsMarked( true );
+                   if ( elemsByFacet[ iE ]->GetType() == bordElem->GetType() )
+                     nextBordElem = elemsByFacet[ iE ];
+                 }
+             }
+           }
+           bordElem = nextBordElem;
+         } // while ( bordElem )
+         linkedBorders.clear(); // not to treat this link any more
+       } // loop on SubBorder's of a FissureBorder
+       bord->Clear();
+     } // loop on FissureBorder's
+     // add elements sharing only one node of the fissure, except those sharing fissure edge nodes
+     // mark nodes of theAffectedElems
+     SMESH_MeshAlgos::MarkElemNodes( theAffectedElems.begin(), theAffectedElems.end(), true );
+     // unmark nodes of the fissure
+     elIt = theElemsOrNodes.begin();
+     if ( (*elIt)->GetType() == SMDSAbs_Node )
+       SMESH_MeshAlgos::MarkElems( elIt, theElemsOrNodes.end(), false );
+     else
+       SMESH_MeshAlgos::MarkElemNodes( elIt, theElemsOrNodes.end(), false );
+     std::vector< gp_XYZ > normVec;
+     // loop on nodes of the fissure, add elements having marked nodes
+     for ( elIt = theElemsOrNodes.begin(); elIt != theElemsOrNodes.end(); ++elIt )
+     {
+       const SMDS_MeshElement* e = (*elIt);
+       if ( e->GetType() != SMDSAbs_Node )
+         e->setIsMarked( true ); // avoid adding a fissure element
+       for ( int iN = 0, nbN = e->NbCornerNodes(); iN < nbN; ++iN )
+       {
+         const SMDS_MeshNode* n = e->GetNode( iN );
+         if ( fissEdgeNodes2Norm.count( n ))
+           continue;
+         SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
+         while ( invIt->more() )
+         {
+           const SMDS_MeshElement* eInv = invIt->next();
+           if ( eInv->isMarked() ) continue;
+           eInv->setIsMarked( true );
+           SMDS_ElemIteratorPtr nIt = eInv->nodesIterator();
+           while( nIt->more() )
+             if ( nIt->next()->isMarked())
+             {
+               theAffectedElems.insert( eInv );
+               SMESH_MeshAlgos::MarkElems( eInv->nodesIterator(), true );
+               n->setIsMarked( false );
+               break;
+             }
+         }
+       }
+     }
+     // add elements on the fissure edge
+     std::map< const SMDS_MeshNode*, FissureNormal >::iterator n2N;
+     for ( n2N = fissEdgeNodes2Norm.begin(); n2N != fissEdgeNodes2Norm.end(); ++n2N )
+     {
+       const SMDS_MeshNode* edgeNode = n2N->first;
+       const FissureNormal & normals = n2N->second;
+       SMDS_ElemIteratorPtr invIt = edgeNode->GetInverseElementIterator();
+       while ( invIt->more() )
+       {
+         const SMDS_MeshElement* eInv = invIt->next();
+         if ( eInv->isMarked() ) continue;
+         eInv->setIsMarked( true );
+         // classify eInv using normals
+         bool toAdd = normals.IsIn( edgeNode, eInv );
+         if ( toAdd ) // check if all nodes lie on the fissure edge
+         {
+           bool notOnEdge = false;
+           for ( int iN = 0, nbN = eInv->NbCornerNodes(); iN < nbN  && !notOnEdge; ++iN )
+             notOnEdge = !fissEdgeNodes2Norm.count( eInv->GetNode( iN ));
+           toAdd = notOnEdge;
+         }
+         if ( toAdd )
+         {
+           theAffectedElems.insert( eInv );
+         }
+       }
+     }
+     return;
+   } // findAffectedElems()
+ } // namespace
  //================================================================================
  /*!
   * \brief Create elements equal (on same nodes) to given ones
@@@ -10616,7 -11163,6 +11166,6 @@@ void SMESH_MeshEditor::DoubleElements( 
  
    SMDSAbs_ElementType type = SMDSAbs_All;
    SMDS_ElemIteratorPtr elemIt;
-   vector< const SMDS_MeshElement* > allElems;
    if ( theElements.empty() )
    {
      if ( mesh->NbNodes() == 0 )
          type = types[i];
          break;
        }
-     // put all elements in the vector <allElems>
-     allElems.reserve( mesh->GetMeshInfo().NbElements( type ));
      elemIt = mesh->elementsIterator( type );
-     while ( elemIt->more() )
-       allElems.push_back( elemIt->next());
-     elemIt = elemSetIterator( allElems );
    }
    else
    {
@@@ -10679,8 -11220,7 +11223,7 @@@ bool SMESH_MeshEditor::DoubleNodes( con
                                      const TIDSortedElemSet& theNodesNot,
                                      const TIDSortedElemSet& theAffectedElems )
  {
-   myLastCreatedElems.Clear();
-   myLastCreatedNodes.Clear();
+   ClearLastCreated();
  
    if ( theElems.size() == 0 )
      return false;
@@@ -10725,8 -11265,8 +11268,8 @@@ bool SMESH_MeshEditor::doubleNodes(SMES
    for ( ;  elemItr != theElems.end(); ++elemItr )
    {
      const SMDS_MeshElement* anElem = *elemItr;
-     if (!anElem)
-       continue;
+     // if (!anElem)
+     //   continue;
  
      // duplicate nodes to duplicate element
      bool isDuplicate = false;
  bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
                                      const std::list< int >& theListOfModifiedElems )
  {
-   myLastCreatedElems.Clear();
-   myLastCreatedNodes.Clear();
+   ClearLastCreated();
  
    if ( theListOfNodes.size() == 0 )
      return false;
    std::list< int >::const_iterator aNodeIter;
    for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
    {
-     int aCurr = *aNodeIter;
-     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
+     const SMDS_MeshNode* aNode = aMeshDS->FindNode( *aNodeIter );
      if ( !aNode )
        continue;
  
      }
    }
  
-   // Create map of new nodes for modified elements
+   // Change nodes of elements
  
-   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
+   std::vector<const SMDS_MeshNode*> aNodeArr;
  
    std::list< int >::const_iterator anElemIter;
-   for ( anElemIter = theListOfModifiedElems.begin();
-         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
+   for ( anElemIter =  theListOfModifiedElems.begin();
+         anElemIter != theListOfModifiedElems.end();
+         anElemIter++ )
    {
-     int aCurr = *anElemIter;
-     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
+     const SMDS_MeshElement* anElem = aMeshDS->FindElement( *anElemIter );
      if ( !anElem )
        continue;
  
-     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
-     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
-     int ind = 0;
-     while ( anIter->more() )
+     aNodeArr.assign( anElem->begin_nodes(), anElem->end_nodes() );
+     for( size_t i = 0; i < aNodeArr.size(); ++i )
      {
-       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
-       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
-       {
-         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
-         aNodeArr[ ind++ ] = aNewNode;
-       }
-       else
-         aNodeArr[ ind++ ] = aCurrNode;
-     }
-     anElemToNodes[ anElem ] = aNodeArr;
-   }
-   // Change nodes of elements
-   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
-     anElemToNodesIter = anElemToNodes.begin();
-   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
-   {
-     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
-     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
-     if ( anElem )
-     {
-       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
+       std::map< const SMDS_MeshNode*, const SMDS_MeshNode* >::iterator n2n =
+         anOldNodeToNewNode.find( aNodeArr[ i ]);
+       if ( n2n != anOldNodeToNewNode.end() )
+         aNodeArr[ i ] = n2n->second;
      }
+     aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], aNodeArr.size() );
    }
  
    return true;
@@@ -10877,8 -11394,8 +11397,8 @@@ namespace 
    {
      gp_XYZ centerXYZ (0, 0, 0);
      SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
-     while (aNodeItr->more())
-       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
+     while ( aNodeItr->more() )
+       centerXYZ += SMESH_NodeXYZ( aNodeItr->next() );
  
      gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
      theClassifier.Perform(aPnt, theTol);
           (select elements with a gravity center on the side given by faces normals).
           This mode (null shape) is faster, but works only when theElems are faces, with coherents orientations.
           The replicated nodes should be associated to affected elements.
-   \return groups of affected elements
+   \return true
    \sa DoubleNodeElemGroupsInRegion()
 */
+ */
  //================================================================================
  
  bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
  {
    if ( theShape.IsNull() )
    {
-     std::set<const SMDS_MeshNode*> alreadyCheckedNodes;
-     std::set<const SMDS_MeshElement*> alreadyCheckedElems;
-     std::set<const SMDS_MeshElement*> edgesToCheck;
-     alreadyCheckedNodes.clear();
-     alreadyCheckedElems.clear();
-     edgesToCheck.clear();
-     // --- iterates on elements to be replicated and get elements by back references from their nodes
-     TIDSortedElemSet::const_iterator elemItr = theElems.begin();
-     for ( ;  elemItr != theElems.end(); ++elemItr )
-     {
-       SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
-       if (!anElem || (anElem->GetType() != SMDSAbs_Face))
-         continue;
-       gp_XYZ normal;
-       SMESH_MeshAlgos::FaceNormal( anElem, normal, /*normalized=*/true );
-       std::set<const SMDS_MeshNode*> nodesElem;
-       nodesElem.clear();
-       SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
-       while ( nodeItr->more() )
-       {
-         const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
-         nodesElem.insert(aNode);
-       }
-       std::set<const SMDS_MeshNode*>::iterator nodit = nodesElem.begin();
-       for (; nodit != nodesElem.end(); nodit++)
-       {
-         const SMDS_MeshNode* aNode = *nodit;
-         if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
-           continue;
-         if (alreadyCheckedNodes.find(aNode) != alreadyCheckedNodes.end())
-           continue;
-         alreadyCheckedNodes.insert(aNode);
-         SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
-         while ( backElemItr->more() )
-         {
-           const SMDS_MeshElement* curElem = backElemItr->next();
-           if (alreadyCheckedElems.find(curElem) != alreadyCheckedElems.end())
-             continue;
-           if (theElems.find(curElem) != theElems.end())
-             continue;
-           alreadyCheckedElems.insert(curElem);
-           double x=0, y=0, z=0;
-           int nb = 0;
-           SMDS_ElemIteratorPtr nodeItr2 = curElem->nodesIterator();
-           while ( nodeItr2->more() )
-           {
-             const SMDS_MeshNode* anotherNode = cast2Node(nodeItr2->next());
-             x += anotherNode->X();
-             y += anotherNode->Y();
-             z += anotherNode->Z();
-             nb++;
-           }
-           gp_XYZ p;
-           p.SetCoord( x/nb -aNode->X(),
-                       y/nb -aNode->Y(),
-                       z/nb -aNode->Z() );
-           if (normal*p > 0)
-           {
-             theAffectedElems.insert( curElem );
-           }
-           else if (curElem->GetType() == SMDSAbs_Edge)
-             edgesToCheck.insert(curElem);
-         }
-       }
-     }
-     // --- add also edges lying on the set of faces (all nodes in alreadyCheckedNodes)
-     std::set<const SMDS_MeshElement*>::iterator eit = edgesToCheck.begin();
-     for( ; eit != edgesToCheck.end(); eit++)
-     {
-       bool onside = true;
-       const SMDS_MeshElement* anEdge = *eit;
-       SMDS_ElemIteratorPtr nodeItr = anEdge->nodesIterator();
-       while ( nodeItr->more() )
-       {
-         const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
-         if (alreadyCheckedNodes.find(aNode) == alreadyCheckedNodes.end())
-         {
-           onside = false;
-           break;
-         }
-       }
-       if (onside)
-       {
-         theAffectedElems.insert(anEdge);
-       }
-     }
+     findAffectedElems( theElems, theAffectedElems );
    }
    else
    {
      TIDSortedElemSet::const_iterator elemItr = theElems.begin();
      for ( ;  elemItr != theElems.end(); ++elemItr )
      {
-       SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
-       if (!anElem)
-         continue;
+       SMDS_MeshElement*     anElem = (SMDS_MeshElement*)*elemItr;
        SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
        while ( nodeItr->more() )
        {
          {
            const SMDS_MeshElement* curElem = backElemItr->next();
            if ( curElem && theElems.find(curElem) == theElems.end() &&
-               ( bsc3d.get() ?
-                 isInside( curElem, *bsc3d, aTol ) :
-                 isInside( curElem, *aFaceClassifier, aTol )))
+                ( bsc3d.get() ?
+                  isInside( curElem, *bsc3d, aTol ) :
+                  isInside( curElem, *aFaceClassifier, aTol )))
              theAffectedElems.insert( curElem );
          }
        }
@@@ -12846,482 -13274,3 +13277,482 @@@ void SMESH_MeshEditor::copyPosition( co
    default:;
    }
  }
 +
 +namespace // utils for MakePolyLine
 +{
 +  //================================================================================
 +  /*!
 +   * \brief Sequence of found points and a current point data
 +   */
 +  struct Path
 +  {
 +    std::vector< gp_XYZ >   myPoints;
 +    double                  myLength;
 +
 +    int                     mySrcPntInd; //!< start point index
 +    const SMDS_MeshElement* myFace;
 +    SMESH_NodeXYZ           myNode1;
 +    SMESH_NodeXYZ           myNode2;
 +    int                     myNodeInd1;
 +    int                     myNodeInd2;
 +    double                  myDot1;
 +    double                  myDot2;
 +    TIDSortedElemSet        myElemSet, myAvoidSet;
 +
 +    Path(): myLength(0.0), myFace(0) {}
 +
 +    bool SetCutAtCorner( const SMESH_NodeXYZ&    cornerNode,
 +                         const SMDS_MeshElement* face,
 +                         const gp_XYZ&           plnNorm,
 +                         const gp_XYZ&           plnOrig );
 +
 +    void AddPoint( const gp_XYZ& p );
 +
 +    bool Extend( const gp_XYZ& plnNorm, const gp_XYZ& plnOrig );
 +
 +    bool ReachSamePoint( const Path& other );
 +
 +    static void Remove( std::vector< Path > & paths, size_t& i );
 +  };
 +
 +  //================================================================================
 +  /*!
 +   * \brief Return true if this Path meats another
 +   */
 +  //================================================================================
 +
 +  bool Path::ReachSamePoint( const Path& other )
 +  {
 +    return ( mySrcPntInd != other.mySrcPntInd &&
 +             myFace == other.myFace );
 +  }
 +
 +  //================================================================================
 +  /*!
 +   * \brief Remove a path from a vector
 +   */
 +  //================================================================================
 +
 +  void Path::Remove( std::vector< Path > & paths, size_t& i )
 +  {
 +    if ( paths.size() > 1 )
 +    {
 +      size_t j = paths.size() - 1; // last item to be removed
 +      if ( i < j )
 +      {
 +        paths[ i ].myPoints.swap( paths[ j ].myPoints );
 +        paths[ i ].myLength    = paths[ j ].myLength;
 +        paths[ i ].mySrcPntInd = paths[ j ].mySrcPntInd;
 +        paths[ i ].myFace      = paths[ j ].myFace;
 +        paths[ i ].myNode1     = paths[ j ].myNode1;
 +        paths[ i ].myNode2     = paths[ j ].myNode2;
 +        paths[ i ].myNodeInd1  = paths[ j ].myNodeInd1;
 +        paths[ i ].myNodeInd2  = paths[ j ].myNodeInd2;
 +        paths[ i ].myDot1      = paths[ j ].myDot1;
 +        paths[ i ].myDot2      = paths[ j ].myDot2;
 +      }
 +    }
 +    paths.pop_back();
 +    if ( i > 0 )
 +      --i;
 +  }
 +
 +  //================================================================================
 +  /*!
 +   * \brief Store a point that is at a node of a face if the face is intersected by plane.
 +   *        Return false if the node is a sole intersection point of the face and the plane
 +   */
 +  //================================================================================
 +
 +  bool Path::SetCutAtCorner( const SMESH_NodeXYZ&    cornerNode,
 +                             const SMDS_MeshElement* face,
 +                             const gp_XYZ&           plnNorm,
 +                             const gp_XYZ&           plnOrig )
 +  {
 +    if ( face == myFace )
 +      return false;
 +    myNodeInd1 = face->GetNodeIndex( cornerNode._node );
 +    myNodeInd2 = ( myNodeInd1 + 1 ) % face->NbCornerNodes();
 +    int   ind3 = ( myNodeInd1 + 2 ) % face->NbCornerNodes();
 +    myNode1.Set( face->GetNode( ind3 ));
 +    myNode2.Set( face->GetNode( myNodeInd2 ));
 +
 +    myDot1 = plnNorm * ( myNode1 - plnOrig );
 +    myDot2 = plnNorm * ( myNode2 - plnOrig );
 +
 +    bool ok = ( myDot1 * myDot2 < 0 );
 +    if ( !ok && myDot1 * myDot2 == 0 )
 +    {
 +      ok = ( myDot1 != myDot2 );
 +      if ( ok && myFace )
 +        ok = ( myFace->GetNodeIndex(( myDot1 == 0 ? myNode1 : myNode2 )._node ) < 0 );
 +    }
 +    if ( ok )
 +    {
 +      myFace = face;
 +      myDot1 = 0;
 +      AddPoint( cornerNode );
 +    }
 +    return ok;
 +  }
 +
 +  //================================================================================
 +  /*!
 +   * \brief Store a point and update myLength
 +   */
 +  //================================================================================
 +
 +  void Path::AddPoint( const gp_XYZ& p )
 +  {
 +    if ( !myPoints.empty() )
 +      myLength += ( p - myPoints.back() ).Modulus();
 +    else
 +      myLength = 0;
 +    myPoints.push_back( p );
 +  }
 +
 +  //================================================================================
 +  /*!
 +   * \brief Try to find the next point
 +   *  \param [in] plnNorm - cutting plane normal
 +   *  \param [in] plnOrig - cutting plane origin
 +   */
 +  //================================================================================
 +
 +  bool Path::Extend( const gp_XYZ& plnNorm, const gp_XYZ& plnOrig )
 +  {
 +    int nodeInd3 = ( myNodeInd1 + 1 ) % myFace->NbCornerNodes();
 +    if ( myNodeInd2 == nodeInd3 )
 +      nodeInd3 = ( myNodeInd1 + 2 ) % myFace->NbCornerNodes();
 +
 +    SMESH_NodeXYZ node3 = myFace->GetNode( nodeInd3 );
 +    double         dot3 = plnNorm * ( node3 - plnOrig );
 +
 +    if ( dot3 * myDot1 < 0. )
 +    {
 +      myNode2    = node3;
 +      myNodeInd2 = nodeInd3;
 +      myDot2     = dot3;
 +    }
 +    else if ( dot3 * myDot2 < 0. )
 +    {
 +      myNode1    = node3;
 +      myNodeInd1 = nodeInd3;
 +      myDot1     = dot3;
 +    }
 +    else if ( dot3 == 0. )
 +    {
 +      SMDS_ElemIteratorPtr fIt = node3._node->GetInverseElementIterator(SMDSAbs_Face);
 +      while ( fIt->more() )
 +        if ( SetCutAtCorner( node3, fIt->next(), plnNorm, plnOrig ))
 +          return true;
 +      return false;
 +    }
 +    else if ( myDot2 == 0. )
 +    {
 +      SMESH_NodeXYZ node2 = myNode2; // copy as myNode2 changes in SetCutAtCorner()
 +      SMDS_ElemIteratorPtr fIt = node2._node->GetInverseElementIterator(SMDSAbs_Face);
 +      while ( fIt->more() )
 +        if ( SetCutAtCorner( node2, fIt->next(), plnNorm, plnOrig ))
 +          return true;
 +      return false;
 +    }
 +
 +    double r = Abs( myDot1 / ( myDot2 - myDot1 ));
 +    AddPoint( myNode1 * ( 1 - r ) + myNode2 * r );
 +
 +    myAvoidSet.clear();
 +    myAvoidSet.insert( myFace );
 +    myFace = SMESH_MeshAlgos::FindFaceInSet( myNode1._node, myNode2._node,
 +                                             myElemSet,   myAvoidSet,
 +                                             &myNodeInd1, &myNodeInd2 );
 +    return myFace;
 +  }
 +
 +  //================================================================================
 +  /*!
 +   * \brief Compute a path between two points of PolySegment
 +   */
 +  struct PolyPathCompute
 +  {
 +    SMESH_MeshEditor::TListOfPolySegments& mySegments; //!< inout PolySegment's
 +    std::vector< Path >&                   myPaths;    //!< path of each of segments to compute
 +    SMESH_Mesh*                            myMesh;
 +    mutable std::vector< std::string >     myErrors;
 +
 +    PolyPathCompute( SMESH_MeshEditor::TListOfPolySegments& theSegments,
 +                     std::vector< Path >&                   thePaths,
 +                     SMESH_Mesh*                            theMesh):
 +      mySegments( theSegments ),
 +      myPaths( thePaths ),
 +      myMesh( theMesh ),
 +      myErrors( theSegments.size() )
 +    {
 +    }
 +#undef SMESH_CAUGHT
 +#define SMESH_CAUGHT myErrors[i] =
 +    void operator() ( const int i ) const
 +    {
 +      SMESH_TRY;
 +      const_cast< PolyPathCompute* >( this )->Compute( i );
 +      SMESH_CATCH( SMESH::returnError );
 +    }
 +#undef SMESH_CAUGHT
 +    //================================================================================
 +    /*!
 +     * \brief Compute a path of a given segment
 +     */
 +    //================================================================================
 +
 +    void Compute( const int iSeg )
 +    {
 +      SMESH_MeshEditor::PolySegment& polySeg = mySegments[ iSeg ];
 +
 +      // get a cutting plane
 +
 +      gp_XYZ p1 = SMESH_NodeXYZ( polySeg.myNode1[0] );
 +      gp_XYZ p2 = SMESH_NodeXYZ( polySeg.myNode1[1] );
 +      if ( polySeg.myNode2[0] ) p1 = 0.5 * ( p1 + SMESH_NodeXYZ( polySeg.myNode2[0] ));
 +      if ( polySeg.myNode2[1] ) p2 = 0.5 * ( p2 + SMESH_NodeXYZ( polySeg.myNode2[1] ));
 +
 +      gp_XYZ plnNorm = ( p1 - p2 ) ^ polySeg.myVector.XYZ();
 +      gp_XYZ plnOrig = p2;
 +
 +      // find paths connecting the 2 end points of polySeg
 +
 +      std::vector< Path > paths; paths.reserve(10);
 +
 +      // initialize paths
 +
 +      for ( int iP = 0; iP < 2; ++iP ) // loop on the polySeg end points
 +      {
 +        Path path;
 +        path.mySrcPntInd = iP;
 +        size_t nbPaths = paths.size();
 +
 +        if ( polySeg.myNode2[ iP ] && polySeg.myNode2[ iP ] != polySeg.myNode1[ iP ] )
 +        {
 +          while (( path.myFace = SMESH_MeshAlgos::FindFaceInSet( polySeg.myNode1[ iP ],
 +                                                                 polySeg.myNode2[ iP ],
 +                                                                 path.myElemSet,
 +                                                                 path.myAvoidSet,
 +                                                                 &path.myNodeInd1,
 +                                                                 &path.myNodeInd2 )))
 +          {
 +            path.myNode1.Set( polySeg.myNode1[ iP ]);
 +            path.myNode2.Set( polySeg.myNode2[ iP ]);
 +            path.myDot1 = plnNorm * ( path.myNode1 - plnOrig );
 +            path.myDot2 = plnNorm * ( path.myNode2 - plnOrig );
 +            path.myPoints.clear();
 +            path.AddPoint( 0.5 * ( path.myNode1 + path.myNode2 ));
 +            path.myAvoidSet.insert( path.myFace );
 +            paths.push_back( path );
 +          }
 +          if ( nbPaths == paths.size() )
 +            throw SALOME_Exception ( SMESH_Comment("No face edge found by point ") << iP+1
 +                                     << " in a PolySegment " << iSeg );
 +        }
 +        else // an end point is at node
 +        {
 +          std::set<const SMDS_MeshNode* > nodes;
 +          SMDS_ElemIteratorPtr fIt = polySeg.myNode1[ iP ]->GetInverseElementIterator(SMDSAbs_Face);
 +          while ( fIt->more() )
 +          {
 +            path.myPoints.clear();
 +            if ( path.SetCutAtCorner( polySeg.myNode1[ iP ], fIt->next(), plnNorm, plnOrig ))
 +            {
 +              if (( path.myDot1 * path.myDot2 != 0 ) ||
 +                  ( nodes.insert( path.myDot1 == 0 ? path.myNode1._node : path.myNode2._node ).second ))
 +                paths.push_back( path );
 +            }
 +          }
 +        }
 +
 +        // look for a one-segment path
 +        for ( size_t i = 0; i < nbPaths; ++i )
 +          for ( size_t j = nbPaths; j < paths.size(); ++j )
 +            if ( paths[i].myFace == paths[j].myFace )
 +            {
 +              myPaths[ iSeg ].myPoints.push_back( paths[i].myPoints[0] );
 +              myPaths[ iSeg ].myPoints.push_back( paths[j].myPoints[0] );
 +              paths.clear();
 +            }
 +      }
 +
 +      // extend paths
 +
 +      myPaths[ iSeg ].myLength = 1e100;
 +
 +      while ( paths.size() >= 2 )
 +      {
 +        for ( size_t i = 0; i < paths.size(); ++i )
 +        {
 +          Path& path = paths[ i ];
 +          if ( !path.Extend( plnNorm, plnOrig ) ||         // path reached a mesh boundary
 +               path.myLength > myPaths[ iSeg ].myLength ) // path is longer than others
 +          {
 +            Path::Remove( paths, i );
 +            continue;
 +          }
 +
 +          // join paths that reach same point
 +          for ( size_t j = 0; j < paths.size(); ++j )
 +          {
 +            if ( i != j && paths[i].ReachSamePoint( paths[j] ))
 +            {
 +              double   distLast = ( paths[i].myPoints.back() - paths[j].myPoints.back() ).Modulus();
 +              double fullLength = ( paths[i].myLength + paths[j].myLength + distLast );
 +              if ( fullLength < myPaths[ iSeg ].myLength )
 +              {
 +                myPaths[ iSeg ].myLength = fullLength;
 +                std::vector< gp_XYZ > & allPoints = myPaths[ iSeg ].myPoints;
 +                allPoints.swap( paths[i].myPoints );
 +                allPoints.insert( allPoints.end(),
 +                                  paths[j].myPoints.rbegin(),
 +                                  paths[j].myPoints.rend() );
 +              }
 +              Path::Remove( paths, i );
 +              Path::Remove( paths, j );
 +            }
 +          }
 +        }
 +        if ( !paths.empty() && (int) paths[0].myPoints.size() > myMesh->NbFaces() )
 +          throw SALOME_Exception(LOCALIZED( "Infinite loop in MakePolyLine()"));
 +      }
 +
 +      if ( myPaths[ iSeg ].myPoints.empty() )
 +        throw SALOME_Exception( SMESH_Comment("Can't find a full path for PolySegment #") << iSeg );
 +
 +    } // PolyPathCompute::Compute()
 +
 +  }; // struct PolyPathCompute
 +
 +} // namespace
 +
 +//=======================================================================
 +//function : MakePolyLine
 +//purpose  : Create a polyline consisting of 1D mesh elements each lying on a 2D element of
 +//           the initial mesh
 +//=======================================================================
 +
 +void SMESH_MeshEditor::MakePolyLine( TListOfPolySegments&   theSegments,
 +                                     SMESHDS_Group*         theGroup,
 +                                     SMESH_ElementSearcher* theSearcher)
 +{
 +  std::vector< Path > segPaths( theSegments.size() ); // path of each of segments
 +
 +  SMESH_ElementSearcher* searcher = theSearcher;
 +  SMESHUtils::Deleter<SMESH_ElementSearcher> delSearcher;
 +  if ( !searcher )
 +  {
 +    searcher = SMESH_MeshAlgos::GetElementSearcher( *GetMeshDS() );
 +    delSearcher._obj = searcher;
 +  }
 +
 +  // get cutting planes
 +
 +  std::vector< bool > isVectorOK( theSegments.size(), true );
 +  const double planarCoef = 0.333; // plane height in planar case
 +
 +  for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg )
 +  {
 +    PolySegment& polySeg = theSegments[ iSeg ];
 +
 +    gp_XYZ p1 = SMESH_NodeXYZ( polySeg.myNode1[0] );
 +    gp_XYZ p2 = SMESH_NodeXYZ( polySeg.myNode1[1] );
 +    if ( polySeg.myNode2[0] ) p1 = 0.5 * ( p1 + SMESH_NodeXYZ( polySeg.myNode2[0] ));
 +    if ( polySeg.myNode2[1] ) p2 = 0.5 * ( p2 + SMESH_NodeXYZ( polySeg.myNode2[1] ));
 +
 +    gp_XYZ plnNorm = ( p1 - p2 ) ^ polySeg.myVector.XYZ();
 +
 +    isVectorOK[ iSeg ] = ( plnNorm.Modulus() > std::numeric_limits<double>::min() );
 +    if ( !isVectorOK[ iSeg ])
 +    {
 +      gp_XYZ pMid = 0.5 * ( p1 + p2 );
 +      const SMDS_MeshElement* face;
 +      polySeg.myMidProjPoint = searcher->Project( pMid, SMDSAbs_Face, &face );
 +      polySeg.myVector       = polySeg.myMidProjPoint.XYZ() - pMid;
 +
 +      gp_XYZ faceNorm;
 +      SMESH_MeshAlgos::FaceNormal( face, faceNorm );
 +
 +      if ( polySeg.myVector.Magnitude() < Precision::Confusion() ||
 +           polySeg.myVector * faceNorm  < Precision::Confusion() )
 +      {
 +        polySeg.myVector = faceNorm;
 +        polySeg.myMidProjPoint = pMid + faceNorm * ( p1 - p2 ).Modulus() * planarCoef;
 +      }
 +    }
 +    else
 +    {
 +      polySeg.myVector = plnNorm ^ ( p1 - p2 );
 +    }
 +  }
 +
 +  // assure that inverse elements are constructed, avoid their concurrent building in threads
 +  GetMeshDS()->nodesIterator()->next()->NbInverseElements();
 +
 +  // find paths
 +
 +  PolyPathCompute algo( theSegments, segPaths, myMesh );
 +  OSD_Parallel::For( 0, theSegments.size(), algo, theSegments.size() == 1 );
 +
 +  for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg )
 +    if ( !algo.myErrors[ iSeg ].empty() )
 +      throw SALOME_Exception( algo.myErrors[ iSeg ].c_str() );
 +
 +  // create an 1D mesh
 +
 +  const SMDS_MeshNode *n, *nPrev = 0;
 +  SMESHDS_Mesh* mesh = GetMeshDS();
 +
 +  for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg )
 +  {
 +    const Path& path = segPaths[iSeg];
 +    if ( path.myPoints.size() < 2 )
 +      continue;
 +
 +    double tol = path.myLength / path.myPoints.size() / 1000.;
 +    if ( !nPrev || ( SMESH_NodeXYZ( nPrev ) - path.myPoints[0] ).SquareModulus() > tol*tol )
 +    {
 +      nPrev = mesh->AddNode( path.myPoints[0].X(), path.myPoints[0].Y(), path.myPoints[0].Z() );
 +      myLastCreatedNodes.Append( nPrev );
 +    }
 +    for ( size_t iP = 1; iP < path.myPoints.size(); ++iP )
 +    {
 +      n = mesh->AddNode( path.myPoints[iP].X(), path.myPoints[iP].Y(), path.myPoints[iP].Z() );
 +      myLastCreatedNodes.Append( n );
 +
 +      const SMDS_MeshElement* elem = mesh->AddEdge( nPrev, n );
 +      myLastCreatedElems.Append( elem );
 +      if ( theGroup )
 +        theGroup->Add( elem );
 +
 +      nPrev = n;
 +    }
 +
 +    // return a vector
 +
 +    gp_XYZ pMid = 0.5 * ( path.myPoints[0] + path.myPoints.back() );
 +    if ( isVectorOK[ iSeg ])
 +    {
 +      // find the most distance point of a path
 +      double maxDist = 0;
 +      for ( size_t iP = 1; iP < path.myPoints.size(); ++iP )
 +      {
 +        double dist = Abs( theSegments[iSeg].myVector * ( path.myPoints[iP] - path.myPoints[0] ));
 +        if ( dist > maxDist )
 +        {
 +          maxDist = dist;
 +          theSegments[iSeg].myMidProjPoint = path.myPoints[iP];
 +        }
 +      }
 +      if ( maxDist < Precision::Confusion() ) // planar case
 +        theSegments[iSeg].myMidProjPoint =
 +          pMid + theSegments[iSeg].myVector.XYZ().Normalized() * path.myLength * planarCoef;
 +    }
 +    theSegments[iSeg].myVector = gp_Vec( pMid, theSegments[iSeg].myMidProjPoint );
 +  }
 +
 +  return;
 +}
index e0c7ad1d2f8b79c6156da4f4a8a41c6aee23316e,9ab185bdbcfe6a907f951ca0a9ef3526690aa9a6..ef6213ce6bd44dbf90d693b37d5e89dfef7ba3ba
          <source>MIN_DIAG_ELEMENTS</source>
          <translation>Minimum diagonal</translation>
      </message>
 +    <message>
 +        <source>MIN_ELEM_EDGE</source>
 +        <translation>Minimum Edge Length</translation>
 +    </message>
      <message>
          <source>ASPECTRATIO_3D_ELEMENTS</source>
          <translation>Aspect Ratio 3D</translation>
          <source>LENGTH2D_EDGES</source>
          <translation>Length 2D</translation>
      </message>
 +    <message>
 +        <source>DEFLECTION2D_FACES</source>
 +        <translation>Deflection 2D</translation>
 +    </message>
      <message>
          <source>LENGTH_EDGES</source>
          <translation>Length</translation>
          <source>MAX_ELEMENT_LENGTH_3D</source>
          <translation>Element Diameter 3D</translation>
      </message>
 +    <message>
 +        <source>DEFLECTION_2D</source>
 +        <translation>Deflection 2D</translation>
 +    </message>
      <message>
          <source>MEN_ADD</source>
          <translation>Add</translation>
          <source>MEN_LENGTH_2D</source>
          <translation>Length 2D</translation>
      </message>
 +    <message>
 +        <source>MEN_DEFLECTION_2D</source>
 +        <translation>Deflection 2D</translation>
 +    </message>
      <message>
          <source>MEN_MAP</source>
          <translation>Pattern Mapping</translation>
@@@ -2148,7 -2132,7 +2148,7 @@@ Check algorithm documentation for suppo
      </message>
      <message>
          <source>SMESH_MESHINFO_ALL_TYPES</source>
 -        <translation>Heterogenous</translation>
 +        <translation>Heterogeneous</translation>
      </message>
      <message>
          <source>SMESH_MESHINFO_EDGES</source>
@@@ -3294,10 -3278,6 +3294,10 @@@ Use Display Entity menu command to sho
          <source>STB_LENGTH_2D</source>
          <translation>Length 2D</translation>
      </message>
 +    <message>
 +        <source>STB_DEFLECTION_2D</source>
 +        <translation>Deflection 2D</translation>
 +    </message>
      <message>
          <source>STB_MAP</source>
          <translation>Pattern mapping</translation>
          <source>TOP_LENGTH_2D</source>
          <translation>Length 2D</translation>
      </message>
 +    <message>
 +        <source>TOP_DEFLECTION_2D</source>
 +        <translation>Deflection 2D</translation>
 +    </message>
      <message>
          <source>TOP_MAP</source>
          <translation>Pattern mapping</translation>
@@@ -5893,10 -5869,6 +5893,10 @@@ Please enter correct value and try agai
          <source>LENGTH2D</source>
          <translation>Length 2D</translation>
      </message>
 +    <message>
 +        <source>DEFLECTION2D</source>
 +        <translation>Deflection 2D</translation>
 +    </message>
      <message>
          <source>LESS_THAN</source>
          <translation>Less than</translation>
@@@ -7240,6 -7212,10 +7240,10 @@@ It is impossible to read point coordina
          <source>ON_ALL_BOUNDARIES</source>
          <translation>On all boundaries</translation>
      </message>
+     <message>
+         <source>GENERATE_GROUPS</source>
+         <translation>Generate</translation>
+     </message>
  </context>
  <context>
      <name>SMESHGUI_Make2DFrom3DDlg</name>
index 6b8f7c6099676a0373ece913676c9cb8c6dc3cef,0bf9c49b5adbb4bdf3f90b83e1fd5b425fe2e8f4..88b1c6d247c8f7d950bded2407e61c4a248069e6
@@@ -100,15 -100,6 +100,15 @@@ struct SMESHUtils_EXPORT SMESH_ElementS
     * \brief Find out if the given point is out of closed 2D mesh.
     */
    virtual TopAbs_State GetPointState(const gp_Pnt& point) = 0;
 +
 +  /*!
 +   * \brief Return a projection of a given point to a 2D mesh.
 +   *        Optionally return the closest face
 +   */
 +  virtual gp_XYZ Project(const gp_Pnt&            point,
 +                         SMDSAbs_ElementType      type,
 +                         const SMDS_MeshElement** closestFace= 0) = 0;
 +
    virtual ~SMESH_ElementSearcher();
  };
  
@@@ -121,16 -112,16 +121,16 @@@ namespace SMESH_MeshAlgo
    bool IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol );
  
    SMESHUtils_EXPORT
 -  double GetDistance( const SMDS_MeshElement* elem, const gp_Pnt& point );
 +  double GetDistance( const SMDS_MeshElement* elem, const gp_Pnt& point, gp_XYZ* closestPnt = 0 );
  
    SMESHUtils_EXPORT
 -  double GetDistance( const SMDS_MeshEdge* edge, const gp_Pnt& point );
 +  double GetDistance( const SMDS_MeshEdge* edge, const gp_Pnt& point, gp_XYZ* closestPnt = 0 );
  
    SMESHUtils_EXPORT
 -  double GetDistance( const SMDS_MeshFace* face, const gp_Pnt& point );
 +  double GetDistance( const SMDS_MeshFace* face, const gp_Pnt& point, gp_XYZ* closestPnt = 0 );
  
    SMESHUtils_EXPORT
 -  double GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt& point );
 +  double GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt& point, gp_XYZ* closestPnt = 0 );
  
    SMESHUtils_EXPORT
    void GetBarycentricCoords( const gp_XY& point,
    SMESHUtils_EXPORT
    std::vector< const SMDS_MeshNode*> GetCommonNodes(const SMDS_MeshElement* e1,
                                                      const SMDS_MeshElement* e2);
 +  /*!
 +   * \brief Return true if node1 encounters first in the face and node2, after.
 +   *        The nodes are supposed to be neighbor nodes in the face.
 +   */
 +  SMESHUtils_EXPORT
 +  bool IsRightOrder( const SMDS_MeshElement* face,
 +                     const SMDS_MeshNode*    node0,
 +                     const SMDS_MeshNode*    node1 );
  
+   /*!
+    * \brief Mark elements given by SMDS_Iterator
+    */
+   template< class ElemIter >
+   void MarkElems( ElemIter it, const bool isMarked )
+   {
+     while ( it->more() ) it->next()->setIsMarked( isMarked );
+   }
+   /*!
+    * \brief Mark elements given by std iterators
+    */
+   template< class ElemIter >
+   void MarkElems( ElemIter it, ElemIter end, const bool isMarked )
+   {
+     for ( ; it != end; ++it ) (*it)->setIsMarked( isMarked );
+   }
+   /*!
+    * \brief Mark nodes of elements given by SMDS_Iterator
+    */
+   template< class ElemIter >
+   void MarkElemNodes( ElemIter it, const bool isMarked, const bool markElem = false )
+   {
+     if ( markElem )
+       while ( it->more() ) {
+         const SMDS_MeshElement* e = it->next();
+         e->setIsMarked( isMarked );
+         MarkElems( e->nodesIterator(), isMarked );
+       }
+     else
+       while ( it->more() )
+         MarkElems( it->next()->nodesIterator(), isMarked );
+   }
+   /*!
+    * \brief Mark elements given by std iterators
+    */
+   template< class ElemIter >
+   void MarkElemNodes( ElemIter it, ElemIter end, const bool isMarked, const bool markElem = false )
+   {
+     if ( markElem )
+       for ( ; it != end; ++it ) {
+         (*it)->setIsMarked( isMarked );
+         MarkElems( (*it)->nodesIterator(), isMarked );
+       }
+     else
+       for ( ; it != end; ++it )
+         MarkElems( (*it)->nodesIterator(), isMarked );
+   }
    /*!
 -   * \brief Return SMESH_NodeSearcher. The caller is responsible for deleteing it
 +   * \brief Return SMESH_NodeSearcher. The caller is responsible for deleting it
     */
    SMESHUtils_EXPORT
    SMESH_NodeSearcher* GetNodeSearcher( SMDS_Mesh& mesh );
    void FindCoincidentFreeBorders(SMDS_Mesh&              mesh,
                                   double                  tolerance,
                                   CoincidentFreeBorders & foundFreeBordes);
 -  
 +  /*!
 +   * Returns all or only closed TFreeBorder's.
 +   * Optionally check if the mesh is manifold and if faces are correctly oriented.
 +   *
 +   * (Implemented in ./SMESH_FreeBorders.cxx)
 +   */
 +  SMESHUtils_EXPORT
 +  void FindFreeBorders(SMDS_Mesh&       mesh,
 +                       TFreeBorderVec & foundFreeBordes,
 +                       const bool       closedOnly,
 +                       bool*            isManifold = 0,
 +                       bool*            isGoodOri = 0);
 +  /*!
 +   * Fill a hole defined by a TFreeBorder with 2D elements.
 +   *
 +   * (Implemented in ./SMESH_FillHole.cxx)
 +   */
 +  SMESHUtils_EXPORT
 +  void FillHole(const TFreeBorder &                   freeBorder,
 +                SMDS_Mesh&                            mesh,
 +                std::vector<const SMDS_MeshElement*>& newFaces);
 +
  
    /*!
     * \brief Find nodes whose merge makes the element invalid
index b5a31ed82c063f719b0b2945e707a8ff3eef92b3,9ae41bf3d4889c6e00d5ee66839adf3a2295f1aa..e7155c2157326b01eca798cf5cf649af80d2fbf4
@@@ -72,7 -72,7 +72,7 @@@ using SMESH::TPythonDump
  
  /*!
   * \brief Container of commands into which the initial script is split.
 - *        It also contains data coresponding to SMESH_Gen contents
 + *        It also contains data corresponding to SMESH_Gen contents
   */
  static Handle(_pyGen) theGen;
  
@@@ -294,8 -294,6 +294,8 @@@ namespace 
      //   - FT_BelongToMeshGroup     = 22
      // v 8.1.0: FT_Undefined == 48, new items:
      //   - FT_NodeConnectivityNumber= 22
 +    // v 8.5.0: FT_Undefined == 49, new items:
 +    //   - FT_Deflection2D          = 22
      //
      // It's necessary to continue recording this history and to fill
      // undef2newItems (see below) accordingly.
        undef2newItems[ 46 ].push_back( 39 );
        undef2newItems[ 47 ].push_back( 22 );
        undef2newItems[ 48 ].push_back( 22 );
 +      undef2newItems[ 49 ].push_back( 22 );
  
        ASSERT( undef2newItems.rbegin()->first == SMESH::FT_Undefined );
      }
@@@ -501,7 -498,7 +501,7 @@@ SMESH_2smeshpy::ConvertScript(std::list
    MESSAGE_BEGIN ( std::endl << " ######## RESULT ######## " << std::endl<< std::endl );
  #endif
  
 -  // clean commmands of removed objects depending on myIsPublished flag
 +  // clean commands of removed objects depending on myIsPublished flag
    theGen->ClearCommands();
  
    // reorder commands after conversion
@@@ -606,7 -603,7 +606,7 @@@ const char* _pyGen::AccessorMethod() co
  //================================================================================
  /*!
   * \brief Convert a command using a specific converter
 -  * \param theCommand - the command to convert
 +  \param theCommand - the command to convert
   */
  //================================================================================
  
@@@ -743,15 -740,16 +743,16 @@@ Handle(_pyCommand) _pyGen::AddCommand( 
      else if ( method == "MakeBoundaryElements")
        meshID = aCommand->GetResultValue(2);
  
-     if ( method.Search("MakeGroups") != -1  ||
-          method == "ExtrusionAlongPathX"    ||
-          method == "ExtrusionAlongPathObjX" ||
-          method == "DoubleNodeGroupNew"     ||
-          method == "DoubleNodeGroupsNew"    ||
-          method == "DoubleNodeElemGroupNew" ||
-          method == "DoubleNodeElemGroupsNew"||
-          method == "DoubleNodeElemGroup2New"||
-          method == "DoubleNodeElemGroups2New"
+     if ( method.Search("MakeGroups") != -1      ||
+          method == "ExtrusionAlongPathX"        ||
+          method == "ExtrusionAlongPathObjX"     ||
+          method == "DoubleNodeGroupNew"         ||
+          method == "DoubleNodeGroupsNew"        ||
+          method == "DoubleNodeElemGroupNew"     ||
+          method == "DoubleNodeElemGroupsNew"    ||
+          method == "DoubleNodeElemGroup2New"    ||
+          method == "DoubleNodeElemGroups2New"   ||
+          method == "AffectedElemGroupsInRegion"
           )
        groups = aCommand->GetResultValue();
      else if ( method == "MakeBoundaryMesh" )
        aCommand->GetString() += tmpCmd.GetString();
      }
      // IMP issue 0021014
 -    // set GetCriterion(elementType,CritType,Compare,Treshold,UnaryOp,BinaryOp,Tolerance)
 -    //                  1           2        3       4        5       6        7
 +    // set GetCriterion(elementType,CritType,Compare,Threshold,UnaryOp,BinaryOp,Tolerance)
 +    //                  1           2        3       4         5       6        7
      // instead of "SMESH.Filter.Criterion(
      // Type,Compare,Threshold,ThresholdStr,ThresholdID,UnaryOp,BinaryOp,Tolerance,TypeOfElement,Precision)
      // 1    2       3         4            5           6       7        8         9             10
  //================================================================================
  /*!
   * \brief Convert the command or remember it for later conversion
 -  * \param theCommand - The python command calling a method of SMESH_Gen
 +  \param theCommand - The python command calling a method of SMESH_Gen
   */
  //================================================================================
  
@@@ -1215,7 -1213,7 +1216,7 @@@ void _pyGen::PlaceSubmeshAfterItsCreati
  
  //================================================================================
  /*!
 - * \brief Clean commmands of removed objects depending on myIsPublished flag
 + * \brief Clean commands of removed objects depending on myIsPublished flag
   */
  //================================================================================
  
@@@ -1278,8 -1276,8 +1279,8 @@@ void _pyGen::Free(
  //================================================================================
  /*!
   * \brief Add access method to mesh that is an argument
 -  * \param theCmd - command to add access method
 -  * \retval bool - true if added
 +  \param theCmd - command to add access method
 + * \retval bool - true if added
   */
  //================================================================================
  
@@@ -1297,8 -1295,8 +1298,8 @@@ bool _pyGen::AddMeshAccessorMethod( Han
  //================================================================================
  /*!
   * \brief Add access method to algo that is an object or an argument
 -  * \param theCmd - command to add access method
 -  * \retval bool - true if added
 +  \param theCmd - command to add access method
 + * \retval bool - true if added
   */
  //================================================================================
  
@@@ -1319,8 -1317,8 +1320,8 @@@ bool _pyGen::AddAlgoAccessorMethod( Han
  //================================================================================
  /*!
   * \brief Find hypothesis by ID (entry)
 -  * \param theHypID - The hypothesis ID
 -  * \retval Handle(_pyHypothesis) - The found hypothesis
 +  \param theHypID - The hypothesis ID
 + * \retval Handle(_pyHypothesis) - The found hypothesis
   */
  //================================================================================
  
@@@ -1337,10 -1335,10 +1338,10 @@@ Handle(_pyHypothesis) _pyGen::FindHyp( 
  //================================================================================
  /*!
   * \brief Find algorithm able to create a hypothesis
 -  * \param theGeom - The shape ID the algorithm was created on
 -  * \param theMesh - The mesh ID that created the algorithm
 -  * \param theHypothesis - The hypothesis the algorithm should be able to create
 -  * \retval Handle(_pyHypothesis) - The found algo
 +  \param theGeom - The shape ID the algorithm was created on
 +  \param theMesh - The mesh ID that created the algorithm
 +  \param theHypothesis - The hypothesis the algorithm should be able to create
 + * \retval Handle(_pyHypothesis) - The found algo
   */
  //================================================================================
  
@@@ -1361,8 -1359,8 +1362,8 @@@ Handle(_pyHypothesis) _pyGen::FindAlgo
  //================================================================================
  /*!
   * \brief Find subMesh by ID (entry)
 -  * \param theSubMeshID - The subMesh ID
 -  * \retval Handle(_pySubMesh) - The found subMesh
 +  \param theSubMeshID - The subMesh ID
 + * \retval Handle(_pySubMesh) - The found subMesh
   */
  //================================================================================
  
@@@ -1378,8 -1376,8 +1379,8 @@@ Handle(_pySubMesh) _pyGen::FindSubMesh
  //================================================================================
  /*!
   * \brief Change order of commands in the script
 -  * \param theCmd1 - One command
 -  * \param theCmd2 - Another command
 +  \param theCmd1 - One command
 +  \param theCmd2 - Another command
   */
  //================================================================================
  
@@@ -1396,15 -1394,15 +1397,15 @@@ void _pyGen::ExchangeCommands( Handle(_
    int nb1 = theCmd1->GetOrderNb();
    theCmd1->SetOrderNb( theCmd2->GetOrderNb() );
    theCmd2->SetOrderNb( nb1 );
 -//   cout << "BECOME " << theCmd1->GetOrderNb() << "\t" << theCmd1->GetString() << endl
 -//        << "BECOME " << theCmd2->GetOrderNb() << "\t" << theCmd2->GetString() << endl << endl;
 +  //   cout << "BECOME " << theCmd1->GetOrderNb() << "\t" << theCmd1->GetString() << endl
 +  //        << "BECOME " << theCmd2->GetOrderNb() << "\t" << theCmd2->GetString() << endl << endl;
  }
  
  //================================================================================
  /*!
   * \brief Set one command after the other
 -  * \param theCmd - Command to move
 -  * \param theAfterCmd - Command ater which to insert the first one
 +  \param theCmd - Command to move
 +  \param theAfterCmd - Command ater which to insert the first one
   */
  //================================================================================
  
@@@ -1416,8 -1414,8 +1417,8 @@@ void _pyGen::SetCommandAfter( Handle(_p
  //================================================================================
  /*!
   * \brief Set one command before the other
 -  * \param theCmd - Command to move
 -  * \param theBeforeCmd - Command before which to insert the first one
 +  \param theCmd - Command to move
 +  \param theBeforeCmd - Command before which to insert the first one
   */
  //================================================================================
  
@@@ -1429,8 -1427,8 +1430,8 @@@ void _pyGen::SetCommandBefore( Handle(_
  //================================================================================
  /*!
   * \brief Set one command before or after the other
 -  * \param theCmd - Command to move
 -  * \param theOtherCmd - Command ater or before which to insert the first one
 +  \param theCmd - Command to move
 +  \param theOtherCmd - Command ater or before which to insert the first one
   */
  //================================================================================
  
@@@ -1457,7 -1455,7 +1458,7 @@@ void _pyGen::setNeighbourCommand( Handl
  
  // void _pyGen::addFilterUser( Handle(_pyCommand)& theCommand, const Handle(_pyObject)& user )
  // {
 -  // No more needed after adding _pyObject::myArgCommands
 +// No more needed after adding _pyObject::myArgCommands
  
  //   const char filterPrefix[] = "aFilter0x";
  //   if ( theCommand->GetString().Search( filterPrefix ) < 1 )
  //================================================================================
  /*!
   * \brief Set command be last in list of commands
 -  * \param theCmd - Command to be last
 +  \param theCmd - Command to be last
   */
  //================================================================================
  
@@@ -1495,8 -1493,8 +1496,8 @@@ Handle(_pyCommand)& _pyGen::GetLastComm
  //================================================================================
  /*!
   * \brief Set method to access to object wrapped with python class
 -  * \param theID - The wrapped object entry
 -  * \param theMethod - The accessor method
 +  \param theID - The wrapped object entry
 +  \param theMethod - The accessor method
   */
  //================================================================================
  
@@@ -1508,7 -1506,7 +1509,7 @@@ void _pyGen::SetAccessorMethod(const _p
  //================================================================================
  /*!
   * \brief Generated new ID for object and assign with existing name
 -  * \param theID - ID of existing object
 +  \param theID - ID of existing object
   */
  //================================================================================
  
@@@ -1548,7 -1546,7 +1549,7 @@@ bool _pyGen::AddObject( Handle(_pyObjec
    }
    else if ( theObj->IsKind( STANDARD_TYPE( _pyMeshEditor ))) {
      add = myMeshEditors.insert( make_pair( theObj->GetID(),
 -                                          Handle(_pyMeshEditor)::DownCast( theObj ))).second;
 +                                           Handle(_pyMeshEditor)::DownCast( theObj ))).second;
    }
    else {
      add = myObjects.insert( make_pair( theObj->GetID(), theObj )).second;
@@@ -1792,7 -1790,7 +1793,7 @@@ _pyMesh::_pyMesh(const Handle(_pyComman
  //================================================================================
  /*!
   * \brief Convert an IDL API command of SMESH::SMESH_Mesh to a method call of python Mesh
 -  * \param theCommand - Engine method called for this mesh
 +  \param theCommand - Engine method called for this mesh
   */
  //================================================================================
  
@@@ -2430,7 -2428,7 +2431,7 @@@ void _pyMeshEditor::Process( const Hand
        "ExtrusionAlongPathX","ExtrusionAlongPathObject1D","ExtrusionAlongPathObject2D",
        "ExtrusionSweepObjects","RotationSweepObjects","ExtrusionAlongPathObjects",
        "Mirror","MirrorObject","Translate","TranslateObject","Rotate","RotateObject",
 -      "FindCoincidentNodes","MergeNodes","FindEqualElements",
 +      "FindCoincidentNodes","MergeNodes","FindEqualElements","FillHole",
        "MergeElements","MergeEqualElements","SewFreeBorders","SewConformFreeBorders",
        "FindCoincidentFreeBorders", "SewCoincidentFreeBorders",
        "SewBorderToSide","SewSideElements","ChangeElemNodes","GetLastCreatedNodes",
        "Scale","ScaleMakeMesh","RotateMakeMesh","RotateObjectMakeMesh","MakeBoundaryMesh",
        "MakeBoundaryElements", "SplitVolumesIntoTetra","SplitHexahedraIntoPrisms",
        "DoubleElements","DoubleNodes","DoubleNode","DoubleNodeGroup","DoubleNodeGroups",
-       "DoubleNodeElem","DoubleNodeElemInRegion","DoubleNodeElemGroup",
+       "DoubleNodeElem","DoubleNodeElemInRegion","DoubleNodeElemGroup","AffectedElemGroupsInRegion",
        "DoubleNodeElemGroupInRegion","DoubleNodeElemGroups","DoubleNodeElemGroupsInRegion",
        "DoubleNodesOnGroupBoundaries","CreateFlatElementsOnFacesGroups","CreateHoleSkin"
        ,"" }; // <- mark of the end
@@@ -2622,7 -2620,7 +2623,7 @@@ bool _pyMeshEditor::CanClear(
  //================================================================================
  /*!
   * \brief _pyHypothesis constructor
 -  * \param theCreationCmd -
 +  \param theCreationCmd -
   */
  //================================================================================
  
@@@ -2635,8 -2633,8 +2636,8 @@@ _pyHypothesis::_pyHypothesis(const Hand
  //================================================================================
  /*!
   * \brief Creates algorithm or hypothesis
 -  * \param theCreationCmd - The engine command creating a hypothesis
 -  * \retval Handle(_pyHypothesis) - Result _pyHypothesis
 +  \param theCreationCmd - The engine command creating a hypothesis
 + * \retval Handle(_pyHypothesis) - Result _pyHypothesis
   */
  //================================================================================
  
@@@ -2725,9 -2723,9 +2726,9 @@@ bool _pyHypothesis::IsWrappable(const _
  //================================================================================
  /*!
   * \brief Convert the command adding a hypothesis to mesh into a smesh command
 -  * \param theCmd - The command like mesh.AddHypothesis( geom, hypo )
 -  * \param theAlgo - The algo that can create this hypo
 -  * \retval bool - false if the command can't be converted
 +  \param theCmd - The command like mesh.AddHypothesis( geom, hypo )
 +  \param theAlgo - The algo that can create this hypo
 + * \retval bool - false if the command can't be converted
   */
  //================================================================================
  
@@@ -2790,7 -2788,7 +2791,7 @@@ bool _pyHypothesis::Addition2Creation( 
  //================================================================================
  /*!
   * \brief Remember hypothesis parameter values
 - * \param theCommand - The called hypothesis method
 + *  \param theCommand - The called hypothesis method
   */
  //================================================================================
  
@@@ -3143,7 -3141,7 +3144,7 @@@ void _pyHypothesis::setCreationArg( con
  //================================================================================
  /*!
   * \brief Remember hypothesis parameter values
 - * \param theCommand - The called hypothesis method
 + *  \param theCommand - The called hypothesis method
   */
  //================================================================================
  
@@@ -3198,8 -3196,8 +3199,8 @@@ void _pyComplexParamHypo::Process( cons
      {
        CreationMethod& crMethod = type2meth->second;
        while ( (int) crMethod.myArgs.size() < i+1 )
 -          crMethod.myArgs.push_back( "[]" );
 -        crMethod.myArgs[ i ] = theCommand->GetArg( 1 ); // arg value
 +        crMethod.myArgs.push_back( "[]" );
 +      crMethod.myArgs[ i ] = theCommand->GetArg( 1 ); // arg value
      }
      myArgCommands.push_back( theCommand );
    }
@@@ -3243,7 -3241,7 +3244,7 @@@ void _pyComplexParamHypo::Flush(
  //================================================================================
  /*!
   * \brief Convert methods of 1D hypotheses to my own methods
 - * \param theCommand - The called hypothesis method
 + *  \param theCommand - The called hypothesis method
   */
  //================================================================================
  
@@@ -3280,9 -3278,9 +3281,9 @@@ void _pyLayerDistributionHypo::Process
  //================================================================================
  /*!
   * \brief
 -  * \param theAdditionCmd - command to be converted
 -  * \param theMesh - mesh instance
 -  * \retval bool - status
 +  \param theAdditionCmd - command to be converted
 +  \param theMesh - mesh instance
 + * \retval bool - status
   */
  //================================================================================
  
@@@ -3384,9 -3382,9 +3385,9 @@@ void _pyLayerDistributionHypo::Flush(
  //================================================================================
  /*!
   * \brief additionally to Addition2Creation, clears SetDistrType() command
 -  * \param theCmd - AddHypothesis() command
 -  * \param theMesh - mesh to which a hypothesis is added
 -  * \retval bool - conversion result
 +  \param theCmd - AddHypothesis() command
 +  \param theMesh - mesh to which a hypothesis is added
 + * \retval bool - conversion result
   */
  //================================================================================
  
@@@ -3466,9 -3464,9 +3467,9 @@@ void _pyNumberOfSegmentsHyp::Flush(
  /*!
   * \brief Convert the command adding "SegmentLengthAroundVertex" to mesh
   * into regular1D.LengthNearVertex( length, vertex )
 -  * \param theCmd - The command like mesh.AddHypothesis( vertex, SegmentLengthAroundVertex )
 -  * \param theMesh - The mesh needing this hypo
 -  * \retval bool - false if the command can't be converted
 +  \param theCmd - The command like mesh.AddHypothesis( vertex, SegmentLengthAroundVertex )
 +  \param theMesh - The mesh needing this hypo
 + * \retval bool - false if the command can't be converted
   */
  //================================================================================
  
@@@ -3511,7 -3509,7 +3512,7 @@@ bool _pySegmentLengthAroundVertexHyp::A
  //================================================================================
  /*!
   * \brief _pyAlgorithm constructor
 - * \param theCreationCmd - The command like "algo = smeshgen.CreateHypothesis(type,lib)"
 + *  \param theCreationCmd - The command like "algo = smeshgen.CreateHypothesis(type,lib)"
   */
  //================================================================================
  
@@@ -3524,9 -3522,9 +3525,9 @@@ _pyAlgorithm::_pyAlgorithm(const Handle
  //================================================================================
  /*!
   * \brief Convert the command adding an algorithm to mesh
 -  * \param theCmd - The command like mesh.AddHypothesis( geom, algo )
 -  * \param theMesh - The mesh needing this algo
 -  * \retval bool - false if the command can't be converted
 +  \param theCmd - The command like mesh.AddHypothesis( geom, algo )
 +  \param theMesh - The mesh needing this algo
 + * \retval bool - false if the command can't be converted
   */
  //================================================================================
  
@@@ -3544,8 -3542,8 +3545,8 @@@ bool _pyAlgorithm::Addition2Creation( c
  //================================================================================
  /*!
   * \brief Return starting position of a part of python command
 -  * \param thePartIndex - The index of command part
 -  * \retval int - Part position
 +  \param thePartIndex - The index of command part
 + * \retval int - Part position
   */
  //================================================================================
  
@@@ -3562,8 -3560,8 +3563,8 @@@ int _pyCommand::GetBegPos( int thePartI
  //================================================================================
  /*!
   * \brief Store starting position of a part of python command
 -  * \param thePartIndex - The index of command part
 -  * \param thePosition - Part position
 +  \param thePartIndex - The index of command part
 +  \param thePosition - Part position
   */
  //================================================================================
  
@@@ -3578,7 -3576,7 +3579,7 @@@ void _pyCommand::SetBegPos( int thePart
  //================================================================================
  /*!
   * \brief Returns whitespace symbols at the line beginning
 -  * \retval TCollection_AsciiString - result
 + * \retval TCollection_AsciiString - result
   */
  //================================================================================
  
@@@ -3595,7 -3593,7 +3596,7 @@@ TCollection_AsciiString _pyCommand::Get
  //================================================================================
  /*!
   * \brief Return substring of python command looking like ResultValue = Obj.Meth()
 -  * \retval const TCollection_AsciiString & - ResultValue substring
 + * \retval const TCollection_AsciiString & - ResultValue substring
   */
  //================================================================================
  
@@@ -3735,7 -3733,7 +3736,7 @@@ const TCollection_AsciiString & _pyComm
  //================================================================================
  /*!
   * \brief Return substring of python command looking like ResVal = Obj.Method()
 -  * \retval const TCollection_AsciiString & - Method substring
 + * \retval const TCollection_AsciiString & - Method substring
   */
  //================================================================================
  
@@@ -3778,7 -3776,7 +3779,7 @@@ bool _pyCommand::IsMethodCall(
  //================================================================================
  /*!
   * \brief Return substring of python command looking like ResVal = Obj.Meth(Arg1,...)
 -  * \retval const TCollection_AsciiString & - Arg<index> substring
 + * \retval const TCollection_AsciiString & - Arg<index> substring
   */
  //================================================================================
  
@@@ -3879,8 -3877,8 +3880,8 @@@ int _pyCommand::GetArgBeginning() cons
  //================================================================================
  /*!
   * \brief Check if char is a word part
 -  * \param c - The character to check
 -  * \retval bool - The check result
 +  \param c - The character to check
 + * \retval bool - The check result
   */
  //================================================================================
  
@@@ -3893,10 -3891,10 +3894,10 @@@ static inline bool isWord(const char c
  //================================================================================
  /*!
   * \brief Looks for a word in the string and returns word's beginning
 -  * \param theString - The input string
 -  * \param theStartPos - The position to start the search, returning word's beginning
 -  * \param theForward - The search direction
 -  * \retval TCollection_AsciiString - The found word
 +  \param theString - The input string
 +  \param theStartPos - The position to start the search, returning word's beginning
 +  \param theForward - The search direction
 + * \retval TCollection_AsciiString - The found word
   */
  //================================================================================
  
@@@ -4027,9 -4025,9 +4028,9 @@@ std::list< _pyID > _pyCommand::GetStudy
  //================================================================================
  /*!
   * \brief Look for position where not space char is
 -  * \param theString - The string
 -  * \param thePos - The position to search from and which returns result
 -  * \retval bool - false if there are only space after thePos in theString
 +  \param theString - The string
 +  \param thePos - The position to search from and which returns result
 + * \retval bool - false if there are only space after thePos in theString
   */
  //================================================================================
  
@@@ -4047,14 -4045,14 +4048,14 @@@ bool _pyCommand::SkipSpaces( const TCol
  //================================================================================
  /*!
   * \brief Modify a part of the command
 -  * \param thePartIndex - The index of the part
 -  * \param thePart - The new part string
 -  * \param theOldPart - The old part
 +  \param thePartIndex - The index of the part
 +  \param thePart - The new part string
 +  \param theOldPart - The old part
   */
  //================================================================================
  
  void _pyCommand::SetPart(int thePartIndex, const TCollection_AsciiString& thePart,
 -                        TCollection_AsciiString& theOldPart)
 +                         TCollection_AsciiString& theOldPart)
  {
    int pos = GetBegPos( thePartIndex );
    if ( pos <= Length() && theOldPart != thePart)
  
  //================================================================================
  /*!
 - * \brief Set agrument
 -  * \param index - The argument index, it counts from 1
 -  * \param theArg - The argument string
 + * \brief Set argument
 +  \param index - The argument index, it counts from 1
 +  \param theArg - The argument string
   */
  //================================================================================
  
@@@ -4189,9 -4187,9 +4190,9 @@@ bool _pyCommand::SetDependentCmdsAfter(
  //================================================================================
  /*!
   * \brief Insert accessor method after theObjectID
 -  * \param theObjectID - id of the accessed object
 -  * \param theAcsMethod - name of the method giving access to the object
 -  * \retval bool - false if theObjectID is not found in the command string
 +  \param theObjectID - id of the accessed object
 +  \param theAcsMethod - name of the method giving access to the object
 + * \retval bool - false if theObjectID is not found in the command string
   */
  //================================================================================
  
@@@ -4279,7 -4277,7 +4280,7 @@@ void _pyObject::ClearCommands(
  //================================================================================
  /*!
   * \brief Return method name giving access to an interaface object wrapped by python class
 -  * \retval const char* - method name
 + * \retval const char* - method name
   */
  //================================================================================
  
@@@ -4411,39 -4409,39 +4412,39 @@@ _pySubMesh::_pySubMesh(const Handle(_py
  bool _pySubMesh::CanBeArgOfMethod(const _AString& theMethodName)
  {
    return false;
 -//   // names of all methods where a sub-mesh can be used as argument
 -//   static TStringSet methods;
 -//   if ( methods.empty() ) {
 -//     const char * names[] = {
 -//       // methods of SMESH_Gen
 -//       "CopyMesh",
 -//       // methods of SMESH_Group
 -//       "AddFrom",
 -//       // methods of SMESH_Measurements
 -//       "MinDistance",
 -//       // methods of SMESH_Mesh
 -//       "ExportPartToMED","ExportCGNS","ExportPartToDAT","ExportPartToUNV","ExportPartToSTL",
 -//       "RemoveSubMesh",
 -//       // methods of SMESH_MeshEditor
 -//       "ReorientObject","Reorient2D","TriToQuadObject","QuadToTriObject","SplitQuadObject",
 -//       "SplitVolumesIntoTetra","SmoothObject","SmoothParametricObject","ConvertFromQuadraticObject",
 -//       "RotationSweepObject","RotationSweepObjectMakeGroups","RotationSweepObject1D",
 -//       "RotationSweepObject1DMakeGroups","RotationSweepObject2D","RotationSweepObject2DMakeGroups",
 -//       "ExtrusionSweepObject","ExtrusionSweepObjectMakeGroups","ExtrusionSweepObject0D",
 -//       "ExtrusionSweepObject0DMakeGroups","ExtrusionSweepObject1D","ExtrusionSweepObject2D",
 -//       "ExtrusionSweepObject1DMakeGroups","ExtrusionSweepObject2DMakeGroups",
 -//       "ExtrusionAlongPathObjX","ExtrusionAlongPathObject","ExtrusionAlongPathObjectMakeGroups",
 -//       "ExtrusionAlongPathObject1D","ExtrusionAlongPathObject1DMakeGroups",
 -//       "ExtrusionAlongPathObject2D","ExtrusionAlongPathObject2DMakeGroups","MirrorObject",
 -//       "MirrorObjectMakeGroups","MirrorObjectMakeMesh","TranslateObject","Scale",
 -//       "TranslateObjectMakeGroups","TranslateObjectMakeMesh","ScaleMakeGroups","ScaleMakeMesh",
 -//       "RotateObject","RotateObjectMakeGroups","RotateObjectMakeMesh","FindCoincidentNodesOnPart",
 -//       "FindCoincidentNodesOnPartBut","FindEqualElements","FindAmongElementsByPoint",
 -//       "MakeBoundaryMesh","Create0DElementsOnAllNodes",
 -//       "" }; // <- mark of end
 -//     methods.Insert( names );
 -//   }
 -//   return methods.Contains( theMethodName );
 +  // names of all methods where a sub-mesh can be used as argument
 +  // static TStringSet methods;
 +  // if ( methods.empty() ) {
 +  //   const char * names[] = {
 +  //     // methods of SMESH_Gen
 +  //     "CopyMesh",
 +  //     // methods of SMESH_Group
 +  //     "AddFrom",
 +  //     // methods of SMESH_Measurements
 +  //     "MinDistance",
 +  //     // methods of SMESH_Mesh
 +  //     "ExportPartToMED","ExportCGNS","ExportPartToDAT","ExportPartToUNV","ExportPartToSTL",
 +  //     "RemoveSubMesh",
 +  //     // methods of SMESH_MeshEditor
 +  //     "ReorientObject","Reorient2D","TriToQuadObject","QuadToTriObject","SplitQuadObject",
 +  //     "SplitVolumesIntoTetra","SmoothObject","SmoothParametricObject","ConvertFromQuadraticObject",
 +  //     "RotationSweepObject","RotationSweepObjectMakeGroups","RotationSweepObject1D",
 +  //     "RotationSweepObject1DMakeGroups","RotationSweepObject2D","RotationSweepObject2DMakeGroups",
 +  //     "ExtrusionSweepObject","ExtrusionSweepObjectMakeGroups","ExtrusionSweepObject0D",
 +  //     "ExtrusionSweepObject0DMakeGroups","ExtrusionSweepObject1D","ExtrusionSweepObject2D",
 +  //     "ExtrusionSweepObject1DMakeGroups","ExtrusionSweepObject2DMakeGroups",
 +  //     "ExtrusionAlongPathObjX","ExtrusionAlongPathObject","ExtrusionAlongPathObjectMakeGroups",
 +  //     "ExtrusionAlongPathObject1D","ExtrusionAlongPathObject1DMakeGroups",
 +  //     "ExtrusionAlongPathObject2D","ExtrusionAlongPathObject2DMakeGroups","MirrorObject",
 +  //     "MirrorObjectMakeGroups","MirrorObjectMakeMesh","TranslateObject","Scale",
 +  //     "TranslateObjectMakeGroups","TranslateObjectMakeMesh","ScaleMakeGroups","ScaleMakeMesh",
 +  //     "RotateObject","RotateObjectMakeGroups","RotateObjectMakeMesh","FindCoincidentNodesOnPart",
 +  //     "FindCoincidentNodesOnPartBut","FindEqualElements","FindAmongElementsByPoint",
 +  //     "MakeBoundaryMesh","Create0DElementsOnAllNodes",
 +  //     "" }; // <- mark of end
 +  //   methods.Insert( names );
 +  // }
 +  // return methods.Contains( theMethodName );
  }
  
  //================================================================================
@@@ -4510,13 -4508,13 +4511,13 @@@ _pyGroup::_pyGroup(const Handle(_pyComm
      //}
      //else {
      // ------------------------->>>>> GroupOnGeom( geom, name, typ )
 -      _pyID type = theCreationCmd->GetArg( 1 );
 -      _pyID name = theCreationCmd->GetArg( 2 );
 -      theCreationCmd->SetMethod( "GroupOnGeom" );
 -      theCreationCmd->RemoveArgs();
 -      theCreationCmd->SetArg( 1, geom );
 -      theCreationCmd->SetArg( 2, name );
 -      theCreationCmd->SetArg( 3, type );
 +    _pyID type = theCreationCmd->GetArg( 1 );
 +    _pyID name = theCreationCmd->GetArg( 2 );
 +    theCreationCmd->SetMethod( "GroupOnGeom" );
 +    theCreationCmd->RemoveArgs();
 +    theCreationCmd->SetArg( 1, geom );
 +    theCreationCmd->SetArg( 2, name );
 +    theCreationCmd->SetArg( 3, type );
      //}
    }
    else if ( method == "CreateGroupFromFilter" )
index 55b451188d212e0b8f6b141a308a4f2dfd52891b,b5a9d4f0654a6be760db0cbb0582d27c4703ea60..6cad2a92eb6c6fed23f9df6f5a0e75e8eca01be2
@@@ -2013,7 -2013,7 +2013,7 @@@ CORBA::Boolean SMESH_MeshEditor_i::Spli
  //=============================================================================
  /*!
   * Find better splitting of the given quadrangle.
 - *  \param IDOfQuad  ID of the quadrangle to be splitted.
 + *  \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.
@@@ -3990,7 -3990,7 +3990,7 @@@ SMESH_MeshEditor_i::ScaleMakeMesh(SMESH
      // 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 );
  
      if ( mesh_i )
@@@ -4577,151 -4577,6 +4577,151 @@@ CORBA::Short SMESH_MeshEditor_i::GetPoi
    return 0;
  }
  
 +//=======================================================================
 +//function : IsManifold
 +//purpose  : Check if a 2D mesh is manifold
 +//=======================================================================
 +
 +CORBA::Boolean SMESH_MeshEditor_i::IsManifold()
 +  throw (SALOME::SALOME_Exception)
 +{
 +  bool isManifold = true;
 +
 +  SMESH_TRY;
 +  SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
 +  SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(),
 +                                    foundFreeBordes,
 +                                    /*closedOnly=*/true,
 +                                    &isManifold );
 +  SMESH_CATCH( SMESH::throwCorbaException );
 +
 +  return isManifold;
 +}
 +
 +//=======================================================================
 +//function : IsCoherentOrientation2D
 +//purpose  : Check if orientation of 2D elements is coherent
 +//=======================================================================
 +
 +CORBA::Boolean SMESH_MeshEditor_i::IsCoherentOrientation2D()
 +  throw (SALOME::SALOME_Exception)
 +{
 +  bool isGoodOri = true;
 +
 +  SMESH_TRY;
 +  SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
 +  SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(),
 +                                    foundFreeBordes,
 +                                    /*closedOnly=*/true,
 +                                    /*isManifold=*/0,
 +                                    &isGoodOri);
 +  SMESH_CATCH( SMESH::throwCorbaException );
 +
 +  return isGoodOri;
 +}
 +
 +//=======================================================================
 +//function : FindFreeBorders
 +//purpose  : Returns all or only closed FreeBorder's.
 +//=======================================================================
 +
 +SMESH::ListOfFreeBorders* SMESH_MeshEditor_i::FindFreeBorders(CORBA::Boolean closedOnly)
 +  throw (SALOME::SALOME_Exception)
 +{
 +  SMESH::ListOfFreeBorders_var resBorders = new SMESH::ListOfFreeBorders;
 +  SMESH_TRY;
 +
 +  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();
 +  }
 +
 +  SMESH_CATCH( SMESH::throwCorbaException );
 +
 +  return resBorders._retn();
 +}
 +
 +//=======================================================================
 +//function : FillHole
 +//purpose  : Fill with 2D elements a hole defined by a FreeBorder.
 +//=======================================================================
 +
 +void SMESH_MeshEditor_i::FillHole(const SMESH::FreeBorder& theHole)
 +  throw (SALOME::SALOME_Exception)
 +{
 +  initData();
 +
 +  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);
 +
 +  SMESH_MeshAlgos::TFreeBorder bordNodes;
 +  bordNodes.resize( theHole.nodeIDs.length() );
 +  for ( size_t iN = 0; iN < theHole.nodeIDs.length(); ++iN )
 +  {
 +    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);
 +  }
 +
 +  SMESH_TRY;
 +
 +  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 )
 +    {
 +      SMDS_ElemIteratorPtr fIt = bordNodes[i]->GetInverseElementIterator( SMDSAbs_Face );
 +      while ( fIt->more() )
 +      {
 +        const SMDS_MeshElement* face = fIt->next();
 +        if ( holeFaces.insert( face ).second )
 +          previewMesh->Copy( face );
 +      }
 +      bordNodes[i] = previewMesh->GetMeshDS()->FindNode( bordNodes[i]->GetID() );
 +      ASSERT( bordNodes[i] );
 +    }
 +    meshDS = previewMesh->GetMeshDS();
 +  }
 +
 +  std::vector<const SMDS_MeshElement*> newFaces;
 +  SMESH_MeshAlgos::FillHole( bordNodes, *meshDS, newFaces );
 +
 +  if ( myIsPreviewMode )
 +  {
 +    previewMesh->Clear();
 +    for ( size_t i = 0; i < newFaces.size(); ++i )
 +      previewMesh->Copy( newFaces[i] );
 +  }
 +  else
 +  {
 +    getEditor().ClearLastCreated();
 +    SMESH_SequenceOfElemPtr& aSeq =
 +      const_cast<SMESH_SequenceOfElemPtr&>( getEditor().GetLastCreatedElems() );
 +    for ( size_t i = 0; i < newFaces.size(); ++i )
 +      aSeq.Append( newFaces[i] );
 +
 +    TPythonDump() << this << ".FillHole( SMESH.FreeBorder(" << theHole.nodeIDs << " ))";
 +  }
 +
 +  SMESH_CATCH( SMESH::throwCorbaException );
 +}
 +
  //=======================================================================
  //function : convError
  //purpose  :
@@@ -5691,10 -5546,7 +5691,7 @@@ CORBA::Boolean SMESH_MeshEditor_i::Doub
    if ( !CORBA::is_nil( theModifiedElems ) )
      aModifiedElems = theModifiedElems->GetListOfID();
    else
-   {
      aModifiedElems = new SMESH::long_array;
-     aModifiedElems->length( 0 );
-   }
  
    TPythonDump pyDump; // suppress dump by the next line
  
@@@ -6407,12 -6259,9 +6404,9 @@@ SMESH_MeshEditor_i::AffectedElemGroupsI
  {
    SMESH_TRY;
    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();
  
  
    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);
  
    declareMeshModified( /*isReComputeSafe=*/ !aResult );
  
    TPythonDump pyDump;
-   if (aResult)
+   if ( aResult && anAffected.size() > 0 )
    {
-     int lg = anAffected.size();
      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);
+     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)
      {
        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;
+       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);
  
-     aNewVolumeGroup->Add(volumeIds);
-     aNewFaceGroup->Add(faceIds);
-     aNewEdgeGroup->Add(edgeIds);
-     isVolumeGroup = (aNewVolumeGroup->Size() > 0);
-     isFaceGroup = (aNewFaceGroup->Size() > 0);
-     isEdgeGroup = (aNewEdgeGroup->Size() > 0);
+     int nbGroups = 0;
+     if ( ivol > 0 )
+     {
+       aNewVolumeGroup = myMesh_i->CreateGroup(SMESH::VOLUME,
+                                               generateGroupName("affectedVolumes").c_str());
+       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);
+       aListOfGroups->length( nbGroups+1 );
+       aListOfGroups[ nbGroups++ ] = aNewFaceGroup._retn();
+     }
+     if ( iedge > 0 )
+     {
+       aNewEdgeGroup = myMesh_i->CreateGroup(SMESH::EDGE,
+                                             generateGroupName("affectedEdges").c_str());
+       aNewEdgeGroup->Add(edgeIds);
+       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
  
-   pyDump << "[ ";
-   if (isEdgeGroup)   pyDump << aNewEdgeGroup << ", ";
-   if (isFaceGroup)   pyDump << aNewFaceGroup << ", ";
-   if (isVolumeGroup) pyDump << aNewVolumeGroup << ", ";
-   pyDump << "] = ";
-   pyDump << this << ".AffectedElemGroupsInRegion( "
+   pyDump << aListOfGroups << " = " << this << ".AffectedElemGroupsInRegion( "
           << &theElems << ", " << &theNodesNot << ", " << theShape << " )";
  
    return aListOfGroups._retn();
  //================================================================================
  /*!
    \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
  */
  //================================================================================
@@@ -6957,130 -6806,3 +6951,130 @@@ CORBA::Long SMESH_MeshEditor_i::MakeBou
    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_MeshEditor::TListOfPolySegments segments( theSegments.length() );
 +  for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
 +  {
 +    SMESH::PolySegment&               segIn = theSegments[ i ];
 +    ::SMESH_MeshEditor::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.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
 +  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
 +  getEditor().MakePolyLine( segments, groupDS, theElementSearcher );
 +
 +  // return vectors
 +  if ( myIsPreviewMode )
 +  {
 +    for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
 +    {
 +      SMESH::PolySegment&             segOut = theSegments[ i ];
 +      ::SMESH_MeshEditor::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;
 +}