Salome HOME
Update of CheckDone
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
index de20777e972c479c26201348ae408d7df60f3720..8c940322e0229a86bdf12fb802492d234ae6f260 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2021  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -62,6 +62,8 @@
 #include <Geom_Curve.hxx>
 #include <Geom_Surface.hxx>
 #include <Precision.hxx>
+#include <ShapeAnalysis.hxx>
+#include <ShapeAnalysis_Curve.hxx>
 #include <TColStd_ListOfInteger.hxx>
 #include <TopAbs_State.hxx>
 #include <TopExp.hxx>
 
 #include "SMESH_TryCatch.hxx" // include after OCCT headers!
 
+#include <smIdType.hxx>
+
 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
 
 using namespace std;
@@ -186,7 +190,7 @@ SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
   SMDS_MeshElement* e = 0;
   int nbnode = node.size();
   SMESHDS_Mesh* mesh = GetMeshDS();
-  const int ID = features.myID;
+  const smIdType ID = features.myID;
 
   switch ( features.myType ) {
   case SMDSAbs_Face:
@@ -389,12 +393,12 @@ SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
  */
 //=======================================================================
 
-SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
-                                               const ElemFeatures& features)
+SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<smIdType> & nodeIDs,
+                                               const ElemFeatures&      features)
 {
   vector<const SMDS_MeshNode*> nodes;
   nodes.reserve( nodeIDs.size() );
-  vector<int>::const_iterator id = nodeIDs.begin();
+  vector<smIdType>::const_iterator id = nodeIDs.begin();
   while ( id != nodeIDs.end() ) {
     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
       nodes.push_back( node );
@@ -410,16 +414,16 @@ SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
 //           Modify a compute state of sub-meshes which become empty
 //=======================================================================
 
-int SMESH_MeshEditor::Remove (const list< int >& theIDs,
-                              const bool         isNodes )
+smIdType SMESH_MeshEditor::Remove (const std::list< smIdType >& theIDs,
+                                   const bool                   isNodes )
 {
   ClearLastCreated();
 
   SMESHDS_Mesh* aMesh = GetMeshDS();
   set< SMESH_subMesh *> smmap;
 
-  int removed = 0;
-  list<int>::const_iterator it = theIDs.begin();
+  smIdType removed = 0;
+  list<smIdType>::const_iterator it = theIDs.begin();
   for ( ; it != theIDs.end(); it++ ) {
     const SMDS_MeshElement * elem;
     if ( isNodes )
@@ -472,10 +476,87 @@ int SMESH_MeshEditor::Remove (const list< int >& theIDs,
   return removed;
 }
 
+//================================================================================
+/*!
+ * \brief Remove a node and fill a hole appeared, by changing surrounding faces
+ */
+//================================================================================
+
+void SMESH_MeshEditor::RemoveNodeWithReconnection( const SMDS_MeshNode* node )
+{
+  if ( ! node )
+    return;
+
+  if ( node->NbInverseElements( SMDSAbs_Volume ) > 0 )
+    throw SALOME_Exception( "RemoveNodeWithReconnection() applies to 2D mesh only" );
+
+  // check that only triangles surround the node
+  for ( SMDS_ElemIteratorPtr fIt = node->GetInverseElementIterator( SMDSAbs_Face ); fIt->more(); )
+  {
+    const SMDS_MeshElement* face = fIt->next();
+    if ( face->GetGeomType() != SMDSGeom_TRIANGLE )
+      throw SALOME_Exception( "RemoveNodeWithReconnection() applies to triangle mesh only" );
+    if ( face->IsQuadratic() )
+      throw SALOME_Exception( "RemoveNodeWithReconnection() applies to linear mesh only" );
+  }
+
+  std::vector< const SMDS_MeshNode*> neighbours(2);
+  SMESH_MeshAlgos::IsOn2DBoundary( node, & neighbours );
+
+  bool toRemove = ( neighbours.size() > 2 ); // non-manifold ==> just remove
+
+  // if ( neighbours.size() == 2 ) // on boundary
+  // {
+  //   // check if theNode and neighbours are on a line
+  //   gp_Pnt pN = SMESH_NodeXYZ( node );
+  //   gp_Pnt p0 = SMESH_NodeXYZ( neighbours[0] );
+  //   gp_Pnt p1 = SMESH_NodeXYZ( neighbours[1] );
+  //   double dist01 = p0.Distance( p1 );
+  //   double    tol = 0.01 * dist01;
+  //   double  distN = ( gp_Vec( p0, p1 ) ^ gp_Vec( p0, pN )).Magnitude() / dist01;
+  //   bool   onLine = distN < tol;
+  //   toRemove = !onLine;
+  // }
+
+  if ( neighbours.empty() ) // not on boundary
+  {
+    TIDSortedElemSet linkedNodes;
+    GetLinkedNodes( node, linkedNodes, SMDSAbs_Face );
+    for ( const SMDS_MeshElement* e : linkedNodes ) neighbours.push_back( cast2Node( e ));
+    if ( neighbours.empty() )
+      toRemove = true;
+  }
+
+  if ( toRemove )
+  {
+    this->Remove( std::list< smIdType >( 1, node->GetID() ), /*isNode=*/true );
+    return;
+  }
+
+  // choose a node to replace by
+  const SMDS_MeshNode* nToReplace = nullptr;
+  SMESH_NodeXYZ           nodeXYZ = node;
+  double                  minDist = Precision::Infinite();
+  for ( const SMDS_MeshNode* n : neighbours )
+  {
+    double dist = nodeXYZ.SquareDistance( n );
+    if ( dist < minDist )
+    {
+      minDist = dist;
+      nToReplace = n;
+    }
+  }
+
+  // remove node + replace by nToReplace
+  std::list< const SMDS_MeshNode* > nodeGroup = { nToReplace, node };
+  TListOfListOfNodes nodesToMerge( 1, nodeGroup );
+  this->MergeNodes( nodesToMerge );
+}
+
 //================================================================================
 /*!
  * \brief Create 0D elements on all nodes of the given object.
- *  \param elements - Elements on whose nodes to create 0D elements; if empty, 
+ *  \param elements - Elements on whose nodes to create 0D elements; if empty,
  *                    the all mesh is treated
  *  \param all0DElems - returns all 0D elements found or created on nodes of \a elements
  *  \param duplicateElements - to add one more 0D element to a node or not
@@ -945,24 +1026,24 @@ bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
 {
   if( tr1->NbNodes() != tr2->NbNodes() )
     return false;
+
   // find the 4-th node to insert into tr1
   const SMDS_MeshNode* n4 = 0;
   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
-  int i=0;
-  while ( !n4 && i<3 ) {
+  for ( int i = 0; !n4 && i < 3; ++i )
+  {
     const SMDS_MeshNode * n = cast2Node( it->next() );
-    i++;
     bool isDiag = ( n == theNode1 || n == theNode2 );
     if ( !isDiag )
       n4 = n;
   }
+
   // Make an array of nodes to be in a quadrangle
   int iNode = 0, iFirstDiag = -1;
   it = tr1->nodesIterator();
-  i=0;
-  while ( i<3 ) {
+  for ( int i = 0; i < 3; ++i )
+  {
     const SMDS_MeshNode * n = cast2Node( it->next() );
-    i++;
     bool isDiag = ( n == theNode1 || n == theNode2 );
     if ( isDiag ) {
       if ( iFirstDiag < 0 )
@@ -1077,6 +1158,210 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
   return true;
 }
 
+//=======================================================================
+//function : SplitEdge
+//purpose  : Replace each triangle bound by theNode1-theNode2 segment with
+//           two triangles by connecting a node made on the link with a node opposite to the link.
+//=======================================================================
+
+void SMESH_MeshEditor::SplitEdge (const SMDS_MeshNode * theNode1,
+                                  const SMDS_MeshNode * theNode2,
+                                  double                thePosition)
+{
+  ClearLastCreated();
+
+  SMESHDS_Mesh * mesh = GetMeshDS();
+
+  // Get triangles and segments to divide
+
+  std::vector<const SMDS_MeshNode *> diagNodes = { theNode1, theNode2 };
+  std::vector<const SMDS_MeshElement *> foundElems;
+  if ( !mesh->GetElementsByNodes( diagNodes, foundElems ) || foundElems.empty() )
+    throw SALOME_Exception( SMESH_Comment("No triangle is bound by the edge ")
+                            << theNode1->GetID() << " - " << theNode2->GetID());
+
+  SMESH_MesherHelper helper( *GetMesh() );
+
+  for ( const SMDS_MeshElement * elem : foundElems )
+  {
+    SMDSAbs_ElementType type = elem->GetType();
+    switch ( type ) {
+    case SMDSAbs_Volume:
+      throw SALOME_Exception( "Can't split an edge of a volume");
+      break;
+
+    case SMDSAbs_Face:
+      if ( elem->GetGeomType() != SMDSGeom_TRIANGLE )
+        throw SALOME_Exception( "Can't split an edge of a face of type other than triangle");
+      if ( elem->IsQuadratic() )
+      {
+        helper.SetIsQuadratic( true );
+        helper.AddTLinks( static_cast< const SMDS_MeshFace*>( elem ));
+        helper.SetIsBiQuadratic( elem->GetEntityType() == SMDSEntity_BiQuad_Triangle );
+      }
+      break;
+
+    case SMDSAbs_Edge:
+      if ( elem->IsQuadratic() )
+      {
+        helper.SetIsQuadratic( true );
+        helper.AddTLinks( static_cast< const SMDS_MeshEdge*>( elem ));
+      }
+      break;
+    default:;
+    }
+  }
+
+  // Make a new node
+
+  const SMDS_MeshNode* nodeOnLink = helper.GetMediumNode( theNode1, theNode2,/*force3d=*/false );
+
+  gp_Pnt newNodeXYZ = ( SMESH_NodeXYZ( theNode1 ) * ( 1 - thePosition ) +
+                        SMESH_NodeXYZ( theNode2 ) * thePosition );
+
+  const TopoDS_Shape& S = mesh->IndexToShape( nodeOnLink->GetShapeID() );
+  if ( !S.IsNull() && S.ShapeType() == TopAbs_FACE ) // find newNodeXYZ by UV on FACE
+  {
+    Handle(ShapeAnalysis_Surface) surface = helper.GetSurface( TopoDS::Face( S ));
+    double  tol = 100 * helper.MaxTolerance( S );
+    gp_Pnt2d uv = surface->ValueOfUV( newNodeXYZ, tol );
+    if ( surface->Gap() < SMESH_NodeXYZ( theNode1 ).Distance( theNode2 ))
+    {
+      newNodeXYZ = surface->Value( uv );
+      if ( SMDS_FacePositionPtr nPos = nodeOnLink->GetPosition())
+        nPos->SetParameters( uv.X(), uv.Y() );
+    }
+  }
+  if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE ) // find newNodeXYZ by param on EDGE
+  {
+    mesh->MoveNode( nodeOnLink, newNodeXYZ.X(), newNodeXYZ.Y(), newNodeXYZ.Z() );
+    double u = Precision::Infinite(), tol = 100 * helper.MaxTolerance( S ), distXYZ[4];
+    helper.ToFixNodeParameters( true );
+    if ( helper.CheckNodeU( TopoDS::Edge( S ), nodeOnLink, u, tol, /*force3D=*/false, distXYZ ))
+      newNodeXYZ.SetCoord( distXYZ[1], distXYZ[2], distXYZ[3] );
+  }
+  mesh->MoveNode( nodeOnLink, newNodeXYZ.X(), newNodeXYZ.Y(), newNodeXYZ.Z() );
+
+  // Split triangles and segments
+
+  std::vector<const SMDS_MeshNode *> nodes( 7 );
+  for ( const SMDS_MeshElement * elem : foundElems )
+  {
+    nodes.assign( elem->begin_nodes(), elem->end_nodes() );
+    nodes.resize( elem->NbCornerNodes() + 1 );
+    nodes.back() = nodes[0];
+
+    smIdType id = elem->GetID();
+    int shapeID = elem->GetShapeID();
+
+    const SMDS_MeshNode* centralNode = nullptr;
+    if ( elem->GetEntityType() == SMDSEntity_BiQuad_Triangle )
+      centralNode = elem->GetNode( 6 );
+
+    mesh->RemoveFreeElement( elem, /*sm=*/0, /*fromGroups=*/false );
+    if ( centralNode )
+      mesh->RemoveFreeNode( centralNode, /*sm=*/0, /*fromGroups=*/true );
+
+    for ( size_t i = 1; i < nodes.size(); ++i )
+    {
+      const SMDS_MeshNode* n1 = nodes[i-1];
+      const SMDS_MeshNode* n2 = nodes[i];
+      const SMDS_MeshElement* newElem;
+      if ( nodes.size() == 4 ) //    triangle
+      {
+        bool isDiag1 = ( n1 == theNode1 || n1 == theNode2 );
+        bool isDiag2 = ( n2 == theNode1 || n2 == theNode2 );
+        if ( isDiag1 && isDiag2 )
+          continue;
+
+        newElem = helper.AddFace( n1, n2, nodeOnLink, id );
+      }
+      else //    segment
+      {
+        newElem = helper.AddEdge( n1, nodeOnLink, id );
+      }
+      myLastCreatedElems.push_back( newElem );
+      AddToSameGroups( newElem, elem, mesh );
+      if ( shapeID )
+        mesh->SetMeshElementOnShape( newElem, shapeID );
+      id = 0;
+    }
+  }
+  return;
+}
+
+//=======================================================================
+//function : SplitFace
+//purpose  : Split a face into triangles each formed by two nodes of the 
+//           face and a new node added at the given coordinates.
+//=======================================================================
+
+void SMESH_MeshEditor::SplitFace (const SMDS_MeshElement * theFace,
+                                  double                   theX,
+                                  double                   theY,
+                                  double                   theZ )
+{
+  ClearLastCreated();
+
+  if ( !theFace )
+    throw SALOME_Exception("Null face given");
+  if ( theFace->GetType() != SMDSAbs_Face )
+    throw SALOME_Exception("Not a face given");
+
+  SMESHDS_Mesh * mesh = GetMeshDS();
+
+  SMESH_MesherHelper helper( *GetMesh() );
+  if ( theFace->IsQuadratic() )
+  {
+    helper.SetIsQuadratic( true );
+    helper.AddTLinks( static_cast< const SMDS_MeshFace*>( theFace ));
+  }
+  const TopoDS_Shape& shape = mesh->IndexToShape( theFace->GetShapeID() );
+  helper.SetSubShape( shape );
+  helper.SetElementsOnShape( true );
+
+  // Make a new node
+
+  const SMDS_MeshNode* centralNode = nullptr;
+  if (      theFace->GetEntityType() == SMDSEntity_BiQuad_Triangle )
+    centralNode = theFace->GetNode( 6 );
+  else if ( theFace->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
+    centralNode = theFace->GetNode( 8 );
+
+  if ( centralNode )
+  {
+    helper.SetIsBiQuadratic( true );
+    mesh->MoveNode( centralNode, theX, theY, theZ );
+  }
+  else
+    centralNode = helper.AddNode( theX, theY, theZ );
+
+
+  // Split theFace
+
+  std::vector<const SMDS_MeshNode *> nodes( theFace->NbNodes() + 1 );
+  nodes.assign( theFace->begin_nodes(), theFace->end_nodes() );
+  nodes.resize( theFace->NbCornerNodes() + 1 );
+  nodes.back() = nodes[0];
+
+  smIdType id = theFace->GetID();
+  int shapeID = theFace->GetShapeID();
+
+  mesh->RemoveFreeElement( theFace, /*sm=*/0, /*fromGroups=*/false );
+
+  for ( size_t i = 1; i < nodes.size(); ++i )
+  {
+    const SMDS_MeshElement* newElem = helper.AddFace( nodes[i-1], nodes[i], centralNode, id );
+
+    myLastCreatedElems.push_back( newElem );
+    AddToSameGroups( newElem, theFace, mesh );
+    if ( shapeID )
+      mesh->SetMeshElementOnShape( newElem, shapeID );
+    id = 0;
+  }
+  return;
+}
+
 //=======================================================================
 //function : Reorient
 //purpose  : Reverse theElement orientation
@@ -1159,69 +1444,88 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
 /*!
  * \brief Reorient faces.
  * \param theFaces - the faces to reorient. If empty the whole mesh is meant
- * \param theDirection - desired direction of normal of \a theFace
- * \param theFace - one of \a theFaces that should be oriented according to
- *        \a theDirection and whose orientation defines orientation of other faces
+ * \param theDirection - desired direction of normal of \a theRefFaces.
+ *        It can be (0,0,0) in order to keep orientation of \a theRefFaces.
+ * \param theRefFaces - correctly oriented faces whose orientation defines
+ *        orientation of other faces.
  * \return number of reoriented faces.
  */
 //================================================================================
 
-int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
-                                  const gp_Dir&            theDirection,
-                                  const SMDS_MeshElement * theFace)
+int SMESH_MeshEditor::Reorient2D( TIDSortedElemSet &  theFaces,
+                                  const gp_Vec&       theDirection,
+                                  TIDSortedElemSet &  theRefFaces,
+                                  bool                theAllowNonManifold )
 {
   int nbReori = 0;
-  if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori;
 
   if ( theFaces.empty() )
   {
-    SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=true*/);
+    SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator();
     while ( fIt->more() )
       theFaces.insert( theFaces.end(), fIt->next() );
+
+    if ( theFaces.empty() )
+      return nbReori;
   }
 
-  // orient theFace according to theDirection
-  gp_XYZ normal;
-  SMESH_MeshAlgos::FaceNormal( theFace, normal, /*normalized=*/false );
-  if ( normal * theDirection.XYZ() < 0 )
-    nbReori += Reorient( theFace );
+  // orient theRefFaces according to theDirection
+  if ( theDirection.X() != 0 || theDirection.Y() != 0 || theDirection.Z() != 0 )
+    for ( const SMDS_MeshElement* refFace : theRefFaces )
+    {
+      gp_XYZ normal;
+      SMESH_MeshAlgos::FaceNormal( refFace, normal, /*normalized=*/false );
+      if ( normal * theDirection.XYZ() < 0 )
+        nbReori += Reorient( refFace );
+    }
 
-  // Orient other faces
+  // mark reference faces
+  GetMeshDS()->SetAllCellsNotMarked();
+  for ( const SMDS_MeshElement* refFace : theRefFaces )
+    refFace->setIsMarked( true );
 
-  set< const SMDS_MeshElement* > startFaces, visitedFaces;
-  TIDSortedElemSet avoidSet;
-  set< SMESH_TLink > checkedLinks;
-  pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
+  // erase reference faces from theFaces
+  for ( TIDSortedElemSet::iterator fIt = theFaces.begin(); fIt != theFaces.end(); )
+    if ( (*fIt)->isMarked() )
+      fIt = theFaces.erase( fIt );
+    else
+      ++fIt;
+
+  if ( theRefFaces.empty() )
+  {
+    theRefFaces.insert( *theFaces.begin() );
+    theFaces.erase( theFaces.begin() );
+  }
 
-  if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
-    theFaces.erase( theFace );
-  startFaces.insert( theFace );
+  // Orient theFaces
+
+  // if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
+  //   theFaces.erase( theFace );
 
   int nodeInd1, nodeInd2;
-  const SMDS_MeshElement*           otherFace;
+  const SMDS_MeshElement*           refFace, *otherFace;
   vector< const SMDS_MeshElement* > facesNearLink;
   vector< std::pair< int, int > >   nodeIndsOfFace;
+  TIDSortedElemSet                  avoidSet, emptySet;
+  NCollection_Map< SMESH_TLink, SMESH_TLink > checkedLinks;
 
-  set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
-  while ( !startFaces.empty() )
+  while ( !theRefFaces.empty() )
   {
-    startFace = startFaces.begin();
-    theFace = *startFace;
-    startFaces.erase( startFace );
-    if ( !visitedFaces.insert( theFace ).second )
-      continue;
+    auto refFaceIt = theRefFaces.begin();
+    refFace = *refFaceIt;
+    theRefFaces.erase( refFaceIt );
 
     avoidSet.clear();
-    avoidSet.insert(theFace);
+    avoidSet.insert( refFace );
 
-    NLink link( theFace->GetNode( 0 ), (SMDS_MeshNode *) 0 );
+    NLink link( refFace->GetNode( 0 ), nullptr );
 
-    const int nbNodes = theFace->NbCornerNodes();
-    for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
+    const int nbNodes = refFace->NbCornerNodes();
+    for ( int i = 0; i < nbNodes; ++i ) // loop on links of refFace
     {
-      link.second = theFace->GetNode(( i+1 ) % nbNodes );
-      linkIt_isNew = checkedLinks.insert( link );
-      if ( !linkIt_isNew.second )
+      link.second = refFace->GetNode(( i+1 ) % nbNodes );
+      bool isLinkVisited = checkedLinks.Contains( link );
+      if ( isLinkVisited )
       {
         // link has already been checked and won't be encountered more
         // if the group (theFaces) is manifold
@@ -1229,28 +1533,41 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
       }
       else
       {
+        checkedLinks.Add( link );
+
         facesNearLink.clear();
         nodeIndsOfFace.clear();
+        TIDSortedElemSet::iterator objFaceIt = theFaces.end();
+
         while (( otherFace = SMESH_MeshAlgos::FindFaceInSet( link.first, link.second,
-                                                             theFaces, avoidSet,
+                                                             emptySet, avoidSet,
                                                              &nodeInd1, &nodeInd2 )))
-          if ( otherFace != theFace)
+        {
+          if (( otherFace->isMarked() ) || // ref face
+              (( objFaceIt = theFaces.find( otherFace )) != theFaces.end() )) // object face
           {
             facesNearLink.push_back( otherFace );
             nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 ));
-            avoidSet.insert( otherFace );
           }
+          avoidSet.insert( otherFace );
+        }
         if ( facesNearLink.size() > 1 )
         {
           // NON-MANIFOLD mesh shell !
-          // select a face most co-directed with theFace,
+          if ( !theAllowNonManifold )
+          {
+            throw SALOME_Exception("Non-manifold topology of groups");
+          }
+          // select a face most co-directed with refFace,
           // other faces won't be visited this time
           gp_XYZ NF, NOF;
-          SMESH_MeshAlgos::FaceNormal( theFace, NF, /*normalized=*/false );
+          SMESH_MeshAlgos::FaceNormal( refFace, NF, /*normalized=*/false );
           double proj, maxProj = -1;
-          for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
+          for ( size_t i = 0; i < facesNearLink.size(); ++i )
+          {
             SMESH_MeshAlgos::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
-            if (( proj = Abs( NF * NOF )) > maxProj ) {
+            if (( proj = Abs( NF * NOF )) > maxProj )
+            {
               maxProj = proj;
               otherFace = facesNearLink[i];
               nodeInd1  = nodeIndsOfFace[i].first;
@@ -1258,9 +1575,9 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
             }
           }
           // not to visit rejected faces
-          for ( size_t i = 0; i < facesNearLink.size(); ++i )
-            if ( facesNearLink[i] != otherFace && theFaces.size() > 1 )
-              visitedFaces.insert( facesNearLink[i] );
+          // for ( size_t i = 0; i < facesNearLink.size(); ++i )
+          //   if ( facesNearLink[i] != otherFace && theFaces.size() > 1 )
+          //     visitedFaces.insert( facesNearLink[i] );
         }
         else if ( facesNearLink.size() == 1 )
         {
@@ -1268,20 +1585,36 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
           nodeInd1  = nodeIndsOfFace.back().first;
           nodeInd2  = nodeIndsOfFace.back().second;
         }
-        if ( otherFace && otherFace != theFace)
+        if ( 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 )
+          // link must be reverse in otherFace if orientation of otherFace
+          // is same as that of refFace
+          if ( abs( nodeInd2 - nodeInd1 ) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
           {
+            if ( otherFace->isMarked() )
+              throw SALOME_Exception("Different orientation of reference faces");
             nbReori += Reorient( otherFace );
           }
-          startFaces.insert( otherFace );
+          if ( !otherFace->isMarked() )
+          {
+            theRefFaces.insert( otherFace );
+            if ( objFaceIt != theFaces.end() )
+              theFaces.erase( objFaceIt );
+          }
         }
       }
-      std::swap( link.first, link.second ); // reverse the link
+      link.first = link.second; // reverse the link
+
+    } // loop on links of refFace
+
+    if ( theRefFaces.empty() && !theFaces.empty() )
+    {
+      theRefFaces.insert( *theFaces.begin() );
+      theFaces.erase( theFaces.begin() );
     }
-  }
+
+  } // while ( !theRefFaces.empty() )
+
   return nbReori;
 }
 
@@ -1808,17 +2141,17 @@ namespace
     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
       : _nbSplits(nbTet), _nbCorners(4), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
-       TSplitMethod(const TSplitMethod &splitMethod)
-               : _nbSplits(splitMethod._nbSplits),
-               _nbCorners(splitMethod._nbCorners),
-               _baryNode(splitMethod._baryNode),
-               _ownConn(splitMethod._ownConn),
-               _faceBaryNode(splitMethod._faceBaryNode)
-       {
-               _connectivity = splitMethod._connectivity;
-               const_cast<TSplitMethod&>(splitMethod)._connectivity = nullptr;
-               const_cast<TSplitMethod&>(splitMethod)._ownConn = false;
-       }
+    TSplitMethod(const TSplitMethod &splitMethod)
+      : _nbSplits(splitMethod._nbSplits),
+        _nbCorners(splitMethod._nbCorners),
+        _baryNode(splitMethod._baryNode),
+        _ownConn(splitMethod._ownConn),
+        _faceBaryNode(splitMethod._faceBaryNode)
+    {
+      _connectivity = splitMethod._connectivity;
+      const_cast<TSplitMethod&>(splitMethod)._connectivity = nullptr;
+      const_cast<TSplitMethod&>(splitMethod)._ownConn = false;
+    }
     bool hasFacet( const TTriangleFacet& facet ) const
     {
       if ( _nbCorners == 4 )
@@ -2069,6 +2402,8 @@ namespace
                                     const int        methodFlags,
                                     const int        facetToSplit)
   {
+    TSplitMethod method;
+
     // order of facets in HEX according to SMDS_VolumeTool::Hexa_F :
     // B, T, L, B, R, F
     const int iF = ( facetToSplit < 2 ) ? 0 : 1 + ( facetToSplit-2 ) % 2; // [0,1,2]
@@ -2099,12 +2434,12 @@ namespace
         to4methods[iF]._nbSplits  = 4;
         to4methods[iF]._nbCorners = 6;
       }
-      return to4methods[iF];
+      method = to4methods[iF];
+      to4methods[iF]._connectivity = method._connectivity; // as copy ctor resets _connectivity
+      return method;
     }
     // else if ( methodFlags == HEXA_TO_2_PRISMS )
 
-    TSplitMethod method;
-
     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
 
     const int nbVariants = 2, nbSplits = 2;
@@ -2216,7 +2551,7 @@ namespace
    */
   //=======================================================================
 
-  struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
+  struct TVolumeFaceKey: pair< pair< smIdType, smIdType>, pair< smIdType, smIdType> >
   {
     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
     {
@@ -2276,7 +2611,7 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems,
     TSplitMethod splitMethod = ( facetToSplit < 0  ?
                                  getTetraSplitMethod( volTool, theMethodFlags ) :
                                  getPrismSplitMethod( volTool, theMethodFlags, facetToSplit ));
-       if ( splitMethod._nbSplits < 1 ) continue;
+    if ( splitMethod._nbSplits < 1 ) continue;
 
     // find submesh to add new tetras to
     if ( !subMesh || !subMesh->Contains( elem ))
@@ -3130,10 +3465,10 @@ public:
     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
   {}
 
-  long GetLinkID (const SMDS_MeshNode * n1,
+  smIdType GetLinkID (const SMDS_MeshNode * n1,
                   const SMDS_MeshNode * n2) const
   {
-    return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
+    return ( std::min(n1->GetID(),n2->GetID()) * myMaxID + std::max(n1->GetID(),n2->GetID()));
   }
 
   bool GetNodes (const long             theLinkID,
@@ -3516,6 +3851,68 @@ void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
   }
 }
 
+//=======================================================================
+//function : averageBySurface
+//purpose  : Auxiliar function to treat properly nodes in periodic faces in the laplacian smoother
+//=======================================================================
+void averageBySurface( const Handle(Geom_Surface)& theSurface, const SMDS_MeshNode* refNode, 
+                        TIDSortedElemSet& nodeSet, map< const SMDS_MeshNode*, gp_XY* >& theUVMap, double * coord )
+{
+  if ( theSurface.IsNull() ) 
+  {
+    TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
+    for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) 
+    {
+      const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
+      coord[0] += node->X();
+      coord[1] += node->Y();
+      coord[2] += node->Z();
+    }
+  }
+  else
+  {
+    Standard_Real Umin,Umax,Vmin,Vmax;
+    theSurface->Bounds( Umin, Umax, Vmin, Vmax );
+    ASSERT( theUVMap.find( refNode ) != theUVMap.end() );
+    gp_XY* nodeUV = theUVMap[ refNode ];
+    Standard_Real uref = nodeUV->X();
+    Standard_Real vref = nodeUV->Y();
+
+    TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
+    for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) 
+    {
+      const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
+      ASSERT( theUVMap.find( node ) != theUVMap.end() );
+      gp_XY* uv = theUVMap[ node ];    
+
+      if ( theSurface->IsUPeriodic() || theSurface->IsVPeriodic() )  
+      {          
+        Standard_Real u          = uv->X();
+        Standard_Real v          = uv->Y();                      
+        Standard_Real uCorrected = u;
+        Standard_Real vCorrected = v;
+        bool isUTobeCorrected = (std::fabs( uref - u ) >= 0.7 * std::fabs( Umax - Umin ));
+        bool isVTobeCorrected = (std::fabs( vref - v ) >= 0.7 * std::fabs( Vmax - Vmin ));
+
+        if( isUTobeCorrected  )
+          uCorrected = uref > u ? Umax + std::fabs(Umin - u) : Umin - std::fabs(Umax - u);
+
+        if( isVTobeCorrected )
+          vCorrected = vref > v ? Vmax + std::fabs(Vmin - v) : Vmin - std::fabs(Vmax - v);
+        
+        coord[0] += uCorrected;
+        coord[1] += vCorrected;
+
+      }
+      else
+      {
+        coord[0] += uv->X();
+        coord[1] += uv->Y();
+      }
+    }   
+  }
+}
+
 //=======================================================================
 //function : laplacianSmooth
 //purpose  : pulls theNode toward the center of surrounding nodes directly
@@ -3532,26 +3929,14 @@ void laplacianSmooth(const SMDS_MeshNode*                 theNode,
   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
 
   // compute new coodrs
+  double coord[] = { 0., 0., 0. };  
+
+  averageBySurface( theSurface, theNode, nodeSet, theUVMap, coord );
 
-  double coord[] = { 0., 0., 0. };
-  TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
-  for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
-    const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
-    if ( theSurface.IsNull() ) { // smooth in 3D
-      coord[0] += node->X();
-      coord[1] += node->Y();
-      coord[2] += node->Z();
-    }
-    else { // smooth in 2D
-      ASSERT( theUVMap.find( node ) != theUVMap.end() );
-      gp_XY* uv = theUVMap[ node ];
-      coord[0] += uv->X();
-      coord[1] += uv->Y();
-    }
-  }
   int nbNodes = nodeSet.size();
   if ( !nbNodes )
     return;
+
   coord[0] /= nbNodes;
   coord[1] /= nbNodes;
 
@@ -3561,7 +3946,7 @@ void laplacianSmooth(const SMDS_MeshNode*                 theNode,
     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
     coord[0] = p3d.X();
     coord[1] = p3d.Y();
-    coord[2] = p3d.Z();
+    coord[2] = p3d.Z();    
   }
   else
     coord[2] /= nbNodes;
@@ -3571,6 +3956,72 @@ void laplacianSmooth(const SMDS_MeshNode*                 theNode,
   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
 }
 
+//=======================================================================
+//function : correctTheValue
+//purpose  : Given a boundaries of parametric space determine if the node coordinate (u,v) need correction 
+//            based on the reference coordinate (uref,vref)
+//=======================================================================
+void correctTheValue( Standard_Real Umax, Standard_Real Umin, Standard_Real Vmax, Standard_Real Vmin, 
+                        Standard_Real uref, Standard_Real vref, Standard_Real &u, Standard_Real &v  )
+{
+  bool isUTobeCorrected = (std::fabs( uref - u ) >= 0.7 * std::fabs( Umax - Umin ));
+  bool isVTobeCorrected = (std::fabs( vref - v ) >= 0.7 * std::fabs( Vmax - Vmin ));
+  if ( isUTobeCorrected )
+    u = std::fabs(u-Umin) < 1e-7 ? Umax : Umin;            
+  if ( isVTobeCorrected )
+    v = std::fabs(v-Vmin) < 1e-7 ? Vmax : Vmin;
+}
+
+//=======================================================================
+//function : averageByElement
+//purpose  : Auxiliar function to treat properly nodes in periodic faces in the centroidal smoother
+//=======================================================================
+void averageByElement( const Handle(Geom_Surface)& theSurface, const SMDS_MeshNode* refNode, const SMDS_MeshElement* elem,
+                        map< const SMDS_MeshNode*, gp_XY* >& theUVMap, SMESH::Controls::TSequenceOfXYZ& aNodePoints, 
+                        gp_XYZ& elemCenter )
+{
+  int nn = elem->NbNodes();
+  if(elem->IsQuadratic()) nn = nn/2;
+  int i=0;
+  SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+  Standard_Real Umin,Umax,Vmin,Vmax;
+  while ( i<nn ) 
+  {
+    const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
+    i++;
+    gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
+    aNodePoints.push_back( aP );
+    if ( !theSurface.IsNull() ) // smooth in 2D
+    { 
+      ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
+      gp_XY* uv = theUVMap[ aNode ];
+
+      if ( theSurface->IsUPeriodic() || theSurface->IsVPeriodic() )  
+      {  
+        theSurface->Bounds( Umin, Umax, Vmin, Vmax );
+        Standard_Real u          = uv->X();
+        Standard_Real v          = uv->Y();   
+        bool isSingularPoint     = std::fabs(u - Umin) < 1e-7 || std::fabs(v - Vmin) < 1e-7 || std::fabs(u - Umax) < 1e-7 || std::fabs( v - Vmax ) < 1e-7;
+        if ( !isSingularPoint )
+        {
+          aP.SetCoord( uv->X(), uv->Y(), 0. );
+        }
+        else
+        {
+          gp_XY* refPoint = theUVMap[ refNode ];
+          Standard_Real uref = refPoint->X();
+          Standard_Real vref = refPoint->Y();
+          correctTheValue( Umax, Umin, Vmax, Vmin, uref, vref, u, v ); 
+          aP.SetCoord( u, v, 0. );
+        }        
+      }
+      else
+        aP.SetCoord( uv->X(), uv->Y(), 0. );
+    }    
+    elemCenter += aP;   
+  }
+}
+
 //=======================================================================
 //function : centroidalSmooth
 //purpose  : pulls theNode toward the element-area-weighted centroid of the
@@ -3585,48 +4036,46 @@ void centroidalSmooth(const SMDS_MeshNode*                 theNode,
   SMESH::Controls::Area anAreaFunc;
   double totalArea = 0.;
   int nbElems = 0;
-
   // compute new XYZ
-
+  bool notToMoveNode = false;
+  // Do not correct singular nodes
+  if ( !theSurface.IsNull() && (theSurface->IsUPeriodic() || theSurface->IsVPeriodic()) )
+  { 
+    Standard_Real Umin,Umax,Vmin,Vmax;
+    theSurface->Bounds( Umin, Umax, Vmin, Vmax );
+    gp_XY* uv = theUVMap[ theNode ];
+    Standard_Real u = uv->X();
+    Standard_Real v = uv->Y();   
+    notToMoveNode = std::fabs(u - Umin) < 1e-7 || std::fabs(v - Vmin) < 1e-7 || std::fabs(u - Umax) < 1e-7 || std::fabs( v - Vmax ) < 1e-7;
+  }
+  
   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
-  while ( elemIt->more() )
+  while ( elemIt->more() && !notToMoveNode )
   {
     const SMDS_MeshElement* elem = elemIt->next();
     nbElems++;
 
     gp_XYZ elemCenter(0.,0.,0.);
     SMESH::Controls::TSequenceOfXYZ aNodePoints;
-    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
     int nn = elem->NbNodes();
     if(elem->IsQuadratic()) nn = nn/2;
-    int i=0;
-    //while ( itN->more() ) {
-    while ( i<nn ) {
-      const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
-      i++;
-      gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
-      aNodePoints.push_back( aP );
-      if ( !theSurface.IsNull() ) { // smooth in 2D
-        ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
-        gp_XY* uv = theUVMap[ aNode ];
-        aP.SetCoord( uv->X(), uv->Y(), 0. );
-      }
-      elemCenter += aP;
-    }
+    averageByElement( theSurface, theNode, elem, theUVMap, aNodePoints, elemCenter );
+
     double elemArea = anAreaFunc.GetValue( aNodePoints );
     totalArea += elemArea;
     elemCenter /= nn;
     aNewXYZ += elemCenter * elemArea;
   }
   aNewXYZ /= totalArea;
-  if ( !theSurface.IsNull() ) {
+  
+  if ( !theSurface.IsNull() && !notToMoveNode ) {
     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
   }
 
   // move node
-
-  const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
+  if ( !notToMoveNode )
+    const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
 }
 
 //=======================================================================
@@ -3929,7 +4378,8 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
         if ( !BRep_Tool::IsClosed( edge, face ))
           continue;
         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
-        if ( !sm ) continue;
+        if ( !sm )
+          continue;
         // find out which parameter varies for a node on seam
         double f,l;
         gp_Pnt2d uv1, uv2;
@@ -4303,7 +4753,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
         std::swap( itNN[0],    itNN[1] );
         std::swap( prevNod[0], prevNod[1] );
         std::swap( nextNod[0], nextNod[1] );
-        std::swap( isSingleNode[0], isSingleNode[1] );
+       std::vector<bool>::swap(isSingleNode[0], isSingleNode[1]);
         if ( nbSame > 0 )
           sames[0] = 1 - sames[0];
         iNotSameNode = 1 - iNotSameNode;
@@ -4886,13 +5336,12 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
             else
               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
-#ifdef _DEBUG_
-            if ( !srcEdges.back() )
+
+            if (SALOME::VerbosityActivated() && !srcEdges.back())
             {
               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
-                   << iF << " of volume #" << vTool.ID() << endl;
+                  << iF << " of volume #" << vTool.ID() << endl;
             }
-#endif
           }
         }
         if ( freeInd.empty() )
@@ -6479,13 +6928,12 @@ SMESH_MeshEditor::PGroupIDs SMESH_MeshEditor::Offset( TIDSortedElemSet & theElem
 
   // copy offsetMesh to theTgtMesh
 
-  int idShift = meshDS->MaxNodeID();
+  smIdType idShift = meshDS->MaxNodeID();
   for ( size_t i = 0; i < new2OldNodes.size(); ++i )
     if ( const SMDS_MeshNode* n = new2OldNodes[ i ].first )
     {
-#ifndef _DEBUG_
-      if ( n->NbInverseElements() > 0 )
-#endif
+
+      if (!SALOME::VerbosityActivated() || n->NbInverseElements() > 0 )
       {
         const SMDS_MeshNode* n2 =
           tgtMeshDS->AddNodeWithID( n->X(), n->Y(), n->Z(), idShift + n->GetID() );
@@ -6849,7 +7297,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes,
 
   TNodeNodeMap nodeNodeMap; // node to replace - new node
   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
-  list< int > rmElemIds, rmNodeIds;
+  list< smIdType > rmElemIds, rmNodeIds;
   vector< ElemFeatures > newElemDefs;
 
   // Fill nodeNodeMap and elems
@@ -6948,6 +7396,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes,
   {
     const SMDS_MeshElement* elem = *eIt;
     SMESHDS_SubMesh*          sm = mesh->MeshElements( elem->getshapeId() );
+    bool                 marked = elem->isMarked();
 
     bool keepElem = applyMerge( elem, newElemDefs, nodeNodeMap, /*noHoles=*/false );
     if ( !keepElem )
@@ -6955,9 +7404,19 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes,
 
     for ( size_t i = 0; i < newElemDefs.size(); ++i )
     {
-      if ( i > 0 || !mesh->ChangeElementNodes( elem,
-                                               & newElemDefs[i].myNodes[0],
-                                               newElemDefs[i].myNodes.size() ))
+      bool elemChanged = false;
+      if ( i == 0 )
+      {
+        if ( elem->GetGeomType() == SMDSGeom_POLYHEDRA )
+          elemChanged = mesh->ChangePolyhedronNodes( elem,
+                                                     newElemDefs[i].myNodes,
+                                                     newElemDefs[i].myPolyhedQuantities );
+        else
+          elemChanged = mesh->ChangeElementNodes( elem,
+                                                  & newElemDefs[i].myNodes[0],
+                                                  newElemDefs[i].myNodes.size() );
+      }
+      if ( i > 0 || !elemChanged )
       {
         if ( i == 0 )
         {
@@ -6974,6 +7433,8 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes,
           sm->AddElement( newElem );
         if ( elem != newElem )
           ReplaceElemInGroups( elem, newElem, mesh );
+        if ( marked && newElem )
+          newElem->setIsMarked( true );
       }
     }
   }
@@ -7124,6 +7585,7 @@ bool SMESH_MeshEditor::applyMerge( const SMDS_MeshElement* elem,
         // each face has to be analyzed in order to check volume validity
         if ( const SMDS_MeshVolume* aPolyedre = SMDS_Mesh::DownCast< SMDS_MeshVolume >( elem ))
         {
+          toRemove = false;
           int nbFaces = aPolyedre->NbFaces();
 
           vector<const SMDS_MeshNode *>& poly_nodes = newElemDefs[0].myNodes;
@@ -7444,12 +7906,12 @@ bool SMESH_MeshEditor::applyMerge( const SMDS_MeshElement* elem,
 // purpose : allow comparing elements basing on their nodes
 // ========================================================
 
-class ComparableElement : public boost::container::flat_set< int >
+class ComparableElement : public boost::container::flat_set< smIdType >
 {
-  typedef boost::container::flat_set< int >  int_set;
+  typedef boost::container::flat_set< smIdType >  int_set;
 
   const SMDS_MeshElement* myElem;
-  int                     mySumID;
+  smIdType                mySumID;
   mutable int             myGroupID;
 
 public:
@@ -7460,7 +7922,7 @@ public:
     this->reserve( theElem->NbNodes() );
     for ( SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator(); nodeIt->more(); )
     {
-      int id = nodeIt->next()->GetID();
+      smIdType id = nodeIt->next()->GetID();
       mySumID += id;
       this->insert( id );
     }
@@ -7483,7 +7945,7 @@ public:
 
   static int HashCode(const ComparableElement& se, int limit )
   {
-    return ::HashCode( se.mySumID, limit );
+    return ::HashCode( FromSmIdType<int>(se.mySumID), limit );
   }
   static Standard_Boolean IsEqual(const ComparableElement& se1, const ComparableElement& se2 )
   {
@@ -7508,7 +7970,7 @@ void SMESH_MeshEditor::FindEqualElements( TIDSortedElemSet &        theElements,
   else                       elemIt = SMESHUtils::elemSetIterator( theElements );
 
   typedef NCollection_Map< ComparableElement, ComparableElement > TMapOfElements;
-  typedef std::list<int>                                          TGroupOfElems;
+  typedef std::list<smIdType>                                     TGroupOfElems;
   TMapOfElements               mapOfElements;
   std::vector< TGroupOfElems > arrayOfGroups;
   TGroupOfElems                groupOfElems;
@@ -7554,7 +8016,7 @@ void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElemen
 {
   ClearLastCreated();
 
-  typedef list<int> TListOfIDs;
+  typedef list<smIdType> TListOfIDs;
   TListOfIDs rmElemIds; // IDs of elems to remove
 
   SMESHDS_Mesh* aMesh = GetMeshDS();
@@ -8269,8 +8731,8 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
     TListOfListOfElementsID::iterator itGroups = equalGroups.begin();
     for ( ; itGroups != equalGroups.end(); ++itGroups )
     {
-      list< int >& group = *itGroups;
-      list< int >::iterator id = group.begin();
+      list< smIdType >& group = *itGroups;
+      list< smIdType >::iterator id = group.begin();
       for ( ++id; id != group.end(); ++id )
         if ( const SMDS_MeshElement* seg = GetMeshDS()->FindElement( *id ))
           segments.erase( seg );
@@ -8702,12 +9164,12 @@ namespace
  */
 //=======================================================================
 
-int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
-                                             SMESH_MesherHelper& theHelper,
-                                             const bool          theForce3d)
+smIdType SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
+                                                  SMESH_MesherHelper& theHelper,
+                                                  const bool          theForce3d)
 {
   //MESSAGE("convertElemToQuadratic");
-  int nbElem = 0;
+  smIdType nbElem = 0;
   if( !theSm ) return nbElem;
 
   vector<int> nbNodeInFaces;
@@ -8760,7 +9222,7 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
     }
     // get elem data needed to re-create it
     //
-    const int id      = elem->GetID();
+    const smIdType id = elem->GetID();
     const int nbNodes = elem->NbCornerNodes();
     nodes.assign(elem->begin_nodes(), elem->end_nodes());
     if ( aGeomType == SMDSEntity_Polyhedra )
@@ -8855,7 +9317,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theT
   aHelper.ToFixNodeParameters( true );
 
   // convert elements assigned to sub-meshes
-  int nbCheckedElems = 0;
+  smIdType nbCheckedElems = 0;
   if ( myMesh->HasShapeToMesh() )
   {
     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
@@ -8872,7 +9334,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theT
   }
 
   // convert elements NOT assigned to sub-meshes
-  int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
+  smIdType totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
   if ( nbCheckedElems < totalNbElems ) // not all elements are in sub-meshes
   {
     aHelper.SetElementsOnShape(false);
@@ -8885,7 +9347,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theT
       const SMDS_MeshEdge* edge = aEdgeItr->next();
       if ( !edge->IsQuadratic() )
       {
-        int                  id = edge->GetID();
+        smIdType                  id = edge->GetID();
         const SMDS_MeshNode* n1 = edge->GetNode(0);
         const SMDS_MeshNode* n2 = edge->GetNode(1);
 
@@ -8926,7 +9388,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theT
       if ( alreadyOK )
         continue;
 
-      const int id = face->GetID();
+      const smIdType id = face->GetID();
       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
 
       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
@@ -8982,7 +9444,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theT
           continue;
         }
       }
-      const int id = volume->GetID();
+      const smIdType id = volume->GetID();
       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
       if ( type == SMDSEntity_Polyhedra )
         nbNodeInFaces = static_cast<const SMDS_MeshVolume* >(volume)->GetQuantities();
@@ -9162,7 +9624,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
     if ( alreadyOK ) continue;
 
     const SMDSAbs_ElementType type = elem->GetType();
-    const int                   id = elem->GetID();
+    const smIdType              id = elem->GetID();
     const int              nbNodes = elem->NbCornerNodes();
     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
 
@@ -9223,15 +9685,15 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
 //=======================================================================
 /*!
  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
- * \return int - nb of checked elements
+ * \return smIdType - nb of checked elements
  */
 //=======================================================================
 
-int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
-                                     SMDS_ElemIteratorPtr theItr,
-                                     const int            /*theShapeID*/)
+smIdType SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
+                                          SMDS_ElemIteratorPtr theItr,
+                                          const int            /*theShapeID*/)
 {
-  int nbElem = 0;
+  smIdType nbElem = 0;
   SMESHDS_Mesh* meshDS = GetMeshDS();
   ElemFeatures elemType;
   vector<const SMDS_MeshNode *> nodes;
@@ -9276,7 +9738,7 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
 
 bool SMESH_MeshEditor::ConvertFromQuadratic()
 {
-  int nbCheckedElems = 0;
+  smIdType nbCheckedElems = 0;
   if ( myMesh->HasShapeToMesh() )
   {
     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
@@ -9290,7 +9752,7 @@ bool SMESH_MeshEditor::ConvertFromQuadratic()
     }
   }
 
-  int totalNbElems =
+  smIdType totalNbElems =
     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
   {
@@ -9329,7 +9791,7 @@ void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
   if ( theElements.empty() ) return;
 
   // collect IDs of medium nodes of theElements; some of these nodes will be removed
-  set<int> mediumNodeIDs;
+  set<smIdType> mediumNodeIDs;
   TIDSortedElemSet::iterator eIt = theElements.begin();
   for ( ; eIt != theElements.end(); ++eIt )
   {
@@ -9348,7 +9810,7 @@ void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
 
   // get remaining medium nodes
   TIDSortedNodeSet mediumNodes;
-  set<int>::iterator nIdsIt = mediumNodeIDs.begin();
+  set<smIdType>::iterator nIdsIt = mediumNodeIDs.begin();
   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
       mediumNodes.insert( mediumNodes.end(), n );
@@ -9837,7 +10299,7 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
   if ( aResult != SEW_OK)
     return aResult;
 
-  list< int > nodeIDsToRemove;
+  list< smIdType > nodeIDsToRemove;
   vector< const SMDS_MeshNode*> nodes;
   ElemFeatures elemType;
 
@@ -10237,7 +10699,8 @@ namespace // automatically find theAffectedElems for DoubleNodes()
       if ( maxX < 0 )
       {
         _elems[0]->setIsMarked( false );
-        _elems[1]->setIsMarked( true );
+        if ( _elems[1] )
+          _elems[1]->setIsMarked( true );
       }
     }
 
@@ -10409,7 +10872,11 @@ namespace // automatically find theAffectedElems for DoubleNodes()
     {
       fissure.reserve( theElemsOrNodes.size() );
       for ( ; elIt != theElemsOrNodes.end(); ++elIt )
+      {
         fissure.push_back( std::move( FissureBorder( *elIt, elemsByFacet )));
+        if ( !fissure.back()._elems[1] )
+          fissure.pop_back();
+      }
     }
     if ( fissure.empty() )
       return;
@@ -10772,7 +11239,23 @@ bool SMESH_MeshEditor::doubleNodes(SMESHDS_Mesh*           theMeshDS,
     if ( theIsDoubleElem )
       AddElement( newNodes, elemType.Init( anElem, /*basicOnly=*/false ));
     else
-      theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], newNodes.size() );
+    {
+      // change element nodes
+      const SMDSAbs_EntityType geomType = anElem->GetEntityType();
+      if ( geomType == SMDSEntity_Polyhedra )
+      {
+        // special treatment for polyhedron
+        const SMDS_MeshVolume* aPolyhedron = SMDS_Mesh::DownCast< SMDS_MeshVolume >( anElem );
+        if (!aPolyhedron) {
+          MESSAGE("Warning: bad volumic element");
+          return false;
+        }
+        theMeshDS->ChangePolyhedronNodes( anElem, newNodes, aPolyhedron->GetQuantities() );
+      }
+      else
+        // standard entity type
+        theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], newNodes.size() );
+    }
 
     res = true;
   }
@@ -10916,7 +11399,7 @@ namespace {
   \brief Identify the elements that will be affected by node duplication (actual duplication is not performed).
   This method is the first step of DoubleNodeElemGroupsInRegion.
   \param theElems - list of groups of elements (edges or faces) to be replicated
-  \param theNodesNot - list of groups of nodes not to replicated
+  \param theNodesNot - list of groups of nodes not to replicate
   \param theShape - shape to detect affected elements (element which geometric center
          located on or inside shape). If the shape is null, detection is done on faces orientations
          (select elements with a gravity center on the side given by faces normals).
@@ -11098,16 +11581,9 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
   //     build the list of nodes shared by 2 or more domains, with their domain indexes
 
   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
-  std::map<int,int>celldom; // cell vtkId --> domain
+  std::map<int,int> celldom; // cell vtkId --> domain
   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
-  faceDomains.clear();
-  celldom.clear();
-  cellDomains.clear();
-  nodeDomains.clear();
-  std::map<int,int> emptyMap;
-  std::set<int> emptySet;
-  emptyMap.clear();
 
   //MESSAGE(".. Number of domains :"<<theElems.size());
 
@@ -11157,7 +11633,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
       const SMDS_MeshElement* anElem = *elemItr;
       if (!anElem)
         continue;
-      int vtkId = anElem->GetVtkID();
+      vtkIdType vtkId = anElem->GetVtkID();
       //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
       int neighborsVtkIds[NBMAXNEIGHBORS];
       int downIds[NBMAXNEIGHBORS];
@@ -11165,7 +11641,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
       int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
       for (int n = 0; n < nbNeighbors; n++)
       {
-        int smdsId = meshDS->FromVtkToSmds(neighborsVtkIds[n]);
+        smIdType smdsId = meshDS->FromVtkToSmds(neighborsVtkIds[n]);
         const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
         if (elem && ! domain.count(elem)) // neighbor is in another domain : face is shared
         {
@@ -11217,7 +11693,6 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
       DownIdType face = itface->first;
       //MESSAGE(" --- face " << face.cellId);
       std::set<int> oldNodes;
-      oldNodes.clear();
       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
       std::set<int>::iterator itn = oldNodes.begin();
       for (; itn != oldNodes.end(); ++itn)
@@ -11272,7 +11747,6 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
       DownIdType face = itface->first;
       //MESSAGE(" --- face " << face.cellId);
       std::set<int> oldNodes;
-      oldNodes.clear();
       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
       std::set<int>::iterator itn = oldNodes.begin();
       for (; itn != oldNodes.end(); ++itn)
@@ -11333,7 +11807,6 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
       DownIdType face = itface->first;
       //MESSAGE(" --- face " << face.cellId);
       std::set<int> oldNodes;
-      oldNodes.clear();
       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
       int nbMultipleNodes = 0;
       std::set<int>::iterator itn = oldNodes.begin();
@@ -11394,7 +11867,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
                   const TIDSortedElemSet& domain = (idom == iRestDom) ? theRestDomElems : theElems[idom];
                   for ( int ivol = 0; ivol < nbvol; ivol++ )
                   {
-                    int smdsId = meshDS->FromVtkToSmds(vtkVolIds[ivol]);
+                    smIdType smdsId = meshDS->FromVtkToSmds(vtkVolIds[ivol]);
                     const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
                     if (domain.count(elem))
                     {
@@ -11458,7 +11931,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
 
   //MESSAGE(".. Creation of elements: simple junction");
-  if (createJointElems)
+  if ( createJointElems )
   {
     string joints2DName = "joints2D";
     mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str());
@@ -11473,15 +11946,14 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
       DownIdType face = itface->first;
       std::set<int> oldNodes;
       std::set<int>::iterator itn;
-      oldNodes.clear();
       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
 
-      std::map<int, int> domvol = itface->second;
+      std::map<int, int>          domvol = itface->second;
       std::map<int, int>::iterator itdom = domvol.begin();
-      int dom1 = itdom->first;
+      int     dom1 = itdom->first;
       int vtkVolId = itdom->second;
       itdom++;
-      int dom2 = itdom->first;
+      int           dom2 = itdom->first;
       SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
                                                        nodeQuadDomains);
       stringstream grpname;
@@ -11538,7 +12010,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
     std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
     for (; ite != edgesMultiDomains.end(); ++ite)
     {
-      vector<int> nodes = ite->first;
+      vector<int>    nodes = ite->first;
       vector<int> orderDom = ite->second;
       vector<vtkIdType> orderedNodes;
       if (nodes.size() == 2)
@@ -11575,10 +12047,9 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
 
   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
-  faceOrEdgeDom.clear();
-  feDom.clear();
 
   //MESSAGE(".. Modification of elements");
+  SMDSAbs_ElementType domainType = (*theElems[0].begin())->GetType();
   for (int idomain = idom0; idomain < nbDomains; idomain++)
   {
     std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
@@ -11596,13 +12067,29 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
           continue; // new cells: not to be modified
         DownIdType aCell(downId, vtkType);
         int volParents[1000];
-        int nbvol = grid->GetParentVolumes(volParents, vtkId);
+        int nbvol = 0;
+        nbvol = grid->GetParentVolumes(volParents, vtkId);
+        if ( domainType == SMDSAbs_Volume )
+        {
+          nbvol = grid->GetParentVolumes(volParents, vtkId);
+        }
+        else // domainType == SMDSAbs_Face
+        {
+          const int            nbFaces = grid->getDownArray(vtkType)->getNumberOfUpCells(downId);
+          const int           *upCells = grid->getDownArray(vtkType)->getUpCells(downId);
+          const unsigned char* upTypes = grid->getDownArray(vtkType)->getUpTypes(downId);
+          for (int i=0; i< nbFaces; i++)
+          {
+            int vtkFaceId = grid->getDownArray( upTypes[i] )->getVtkCellId(upCells[i]);
+            if (vtkFaceId >= 0)
+              volParents[nbvol++] = vtkFaceId;
+          }
+        }
         for (int j = 0; j < nbvol; j++)
           if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
             if (!feDom.count(vtkId))
             {
               feDom[vtkId] = idomain;
-              faceOrEdgeDom[aCell] = emptyMap;
               faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
               //MESSAGE("affect cell " << this->GetMeshDS()->FromVtkToSmds(vtkId) << " domain " << idomain
               //        << " type " << vtkType << " downId " << downId);
@@ -11625,7 +12112,6 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
       DownIdType face = itface->first;
       std::set<int> oldNodes;
       std::set<int>::iterator itn;
-      oldNodes.clear();
       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
       //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
       std::map<int, int> localClonedNodeIds;
@@ -11692,10 +12178,7 @@ bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSort
 
   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
-  clonedNodes.clear();
-  intermediateNodes.clear();
   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
-  mapOfJunctionGroups.clear();
 
   for ( size_t idom = 0; idom < theElems.size(); idom++ )
   {
@@ -11942,7 +12425,6 @@ void SMESH_MeshEditor::CreateHoleSkin(double                          radius,
   std::set<int> setOfVolToCheck;
 
   std::vector<gp_Pnt> gpnts;
-  gpnts.clear();
 
   if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
   {
@@ -12029,7 +12511,6 @@ void SMESH_MeshEditor::CreateHoleSkin(double                          radius,
     //     Fill the group of inside volumes
 
     std::map<int, double> mapOfNodeDistance2;
-    mapOfNodeDistance2.clear();
     std::set<int> setOfOutsideVol;
     while (!setOfVolToCheck.empty())
     {
@@ -12206,9 +12687,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double                          radius,
   //     project polylines on subshapes, and partition, to get geom faces
 
   std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
-  std::set<int> emptySet;
-  emptySet.clear();
-  std::set<int> shapeIds;
+  std::set<int>                 shapeIds;
 
   SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
   while (itelem->more())
@@ -12218,7 +12697,6 @@ void SMESH_MeshEditor::CreateHoleSkin(double                          radius,
     int   vtkId = elem->GetVtkID();
     if (!shapeIdToVtkIdSet.count(shapeId))
     {
-      shapeIdToVtkIdSet[shapeId] = emptySet;
       shapeIds.insert(shapeId);
     }
     shapeIdToVtkIdSet[shapeId].insert(vtkId);
@@ -12226,7 +12704,6 @@ void SMESH_MeshEditor::CreateHoleSkin(double                          radius,
 
   std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
   std::set<DownIdType, DownIdCompare> emptyEdges;
-  emptyEdges.clear();
 
   std::map<int, std::set<int> >::iterator itShape =  shapeIdToVtkIdSet.begin();
   for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
@@ -12250,7 +12727,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double                          radius,
       {
         if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
           continue;
-        int smdsId = meshDS->FromVtkToSmds(neighborsVtkIds[n]);
+        smIdType smdsId = meshDS->FromVtkToSmds(neighborsVtkIds[n]);
         const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
         if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
         {
@@ -12269,7 +12746,6 @@ void SMESH_MeshEditor::CreateHoleSkin(double                          radius,
     }
 
     std::list<int> order;
-    order.clear();
     if (nodesEdges.size() > 0)
     {
       order.push_back(nodesEdges[0]); //MESSAGE("       --- back " << order.back()+1); // SMDS id = VTK id + 1;
@@ -12450,7 +12926,8 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
                                        bool                    toCopyElements/*=false*/,
                                        bool                    toCopyExistingBoundary/*=false*/,
                                        bool                    toAddExistingBondary/*= false*/,
-                                       bool                    aroundElements/*= false*/)
+                                       bool                    aroundElements/*= false*/,
+                                       bool                    toCreateAllElements/*= false*/)
 {
   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
@@ -12469,7 +12946,6 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
   SMESH_MeshEditor* presentEditor;
   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
-
   SMESH_MesherHelper helper( *myMesh );
   const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
   SMDS_VolumeTool vTool;
@@ -12507,8 +12983,9 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
       const SMDS_MeshElement* otherVol = 0;
       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
       {
-        if ( !vTool.IsFreeFace(iface, &otherVol) &&
-             ( !aroundElements || elements.count( otherVol )))
+        if ( !toCreateAllElements && 
+              !vTool.IsFreeFace(iface, &otherVol) &&
+                ( !aroundElements || elements.count( otherVol )))
           continue;
         freeFacets.push_back( iface );
       }