Salome HOME
PR: double nodes and flat elements for ASTER calculations in progress
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
index 198cf0f2da50310c81b584dadef6b9cf30c9d36e..0dc929c50d3f38f545eff0353d1dec999b4ca8ab 100644 (file)
@@ -135,27 +135,27 @@ SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
   case SMDSAbs_Face:
     if ( !isPoly ) {
       if      (nbnode == 3) {
-        if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
+        if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
         else           e = mesh->AddFace      (node[0], node[1], node[2] );
       }
       else if (nbnode == 4) {
-        if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
+        if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
       }
       else if (nbnode == 6) {
-        if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
-                                              node[4], node[5], ID);
+        if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
+                                               node[4], node[5], ID);
         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
-                                              node[4], node[5] );
+                                               node[4], node[5] );
       }
       else if (nbnode == 8) {
-        if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
-                                              node[4], node[5], node[6], node[7], ID);
+        if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
+                                               node[4], node[5], node[6], node[7], ID);
         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
-                                              node[4], node[5], node[6], node[7] );
+                                               node[4], node[5], node[6], node[7] );
       }
     } else {
-      if ( ID >= 0 ) e = mesh->AddPolygonalFaceWithID(node, ID);
+      if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
       else           e = mesh->AddPolygonalFace      (node    );
     }
     break;
@@ -163,90 +163,90 @@ SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
   case SMDSAbs_Volume:
     if ( !isPoly ) {
       if      (nbnode == 4) {
-        if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
+        if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
       }
       else if (nbnode == 5) {
-        if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
-                                                node[4], ID);
+        if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+                                                 node[4], ID);
         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
-                                                node[4] );
+                                                 node[4] );
       }
       else if (nbnode == 6) {
-        if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
-                                                node[4], node[5], ID);
+        if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], ID);
         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
-                                                node[4], node[5] );
+                                                 node[4], node[5] );
       }
       else if (nbnode == 8) {
-        if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
-                                                node[4], node[5], node[6], node[7], ID);
+        if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], node[6], node[7], ID);
         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
-                                                node[4], node[5], node[6], node[7] );
+                                                 node[4], node[5], node[6], node[7] );
       }
       else if (nbnode == 10) {
-        if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
-                                                node[4], node[5], node[6], node[7],
-                                                node[8], node[9], ID);
+        if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], node[6], node[7],
+                                                 node[8], node[9], ID);
         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
-                                                node[4], node[5], node[6], node[7],
-                                                node[8], node[9] );
+                                                 node[4], node[5], node[6], node[7],
+                                                 node[8], node[9] );
       }
       else if (nbnode == 13) {
-        if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
-                                                node[4], node[5], node[6], node[7],
-                                                node[8], node[9], node[10],node[11],
-                                                node[12],ID);
+        if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], node[6], node[7],
+                                                 node[8], node[9], node[10],node[11],
+                                                 node[12],ID);
         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
-                                                node[4], node[5], node[6], node[7],
-                                                node[8], node[9], node[10],node[11],
-                                                node[12] );
+                                                 node[4], node[5], node[6], node[7],
+                                                 node[8], node[9], node[10],node[11],
+                                                 node[12] );
       }
       else if (nbnode == 15) {
-        if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
-                                                node[4], node[5], node[6], node[7],
-                                                node[8], node[9], node[10],node[11],
-                                                node[12],node[13],node[14],ID);
+        if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], node[6], node[7],
+                                                 node[8], node[9], node[10],node[11],
+                                                 node[12],node[13],node[14],ID);
         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
-                                                node[4], node[5], node[6], node[7],
-                                                node[8], node[9], node[10],node[11],
-                                                node[12],node[13],node[14] );
+                                                 node[4], node[5], node[6], node[7],
+                                                 node[8], node[9], node[10],node[11],
+                                                 node[12],node[13],node[14] );
       }
       else if (nbnode == 20) {
-        if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
-                                                node[4], node[5], node[6], node[7],
-                                                node[8], node[9], node[10],node[11],
-                                                node[12],node[13],node[14],node[15],
-                                                node[16],node[17],node[18],node[19],ID);
+        if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+                                                 node[4], node[5], node[6], node[7],
+                                                 node[8], node[9], node[10],node[11],
+                                                 node[12],node[13],node[14],node[15],
+                                                 node[16],node[17],node[18],node[19],ID);
         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
-                                                node[4], node[5], node[6], node[7],
-                                                node[8], node[9], node[10],node[11],
-                                                node[12],node[13],node[14],node[15],
-                                                node[16],node[17],node[18],node[19] );
+                                                 node[4], node[5], node[6], node[7],
+                                                 node[8], node[9], node[10],node[11],
+                                                 node[12],node[13],node[14],node[15],
+                                                 node[16],node[17],node[18],node[19] );
       }
     }
     break;
 
   case SMDSAbs_Edge:
     if ( nbnode == 2 ) {
-      if ( ID >= 0 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
+      if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
       else           e = mesh->AddEdge      (node[0], node[1] );
     }
     else if ( nbnode == 3 ) {
-      if ( ID >= 0 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
+      if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
     }
     break;
 
   case SMDSAbs_0DElement:
     if ( nbnode == 1 ) {
-      if ( ID >= 0 ) e = mesh->Add0DElementWithID(node[0], ID);
+      if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
       else           e = mesh->Add0DElement      (node[0] );
     }
     break;
 
   case SMDSAbs_Node:
-    if ( ID >= 0 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
+    if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
     break;
 
@@ -1563,14 +1563,14 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
                                               const int                theMethodFlags)
 {
   // std-like iterator on coordinates of nodes of mesh element
-  typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
+  typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
   NXyzIterator xyzEnd;
 
   SMDS_VolumeTool    volTool;
   SMESH_MesherHelper helper( *GetMesh());
 
-  SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
-  SMESHDS_SubMesh* fSubMesh = subMesh;
+  SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
+  SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
   
   SMESH_SequenceOfElemPtr newNodes, newElems;
 
@@ -2681,6 +2681,9 @@ void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
   while ( elemIt->more() )
   {
     const SMDS_MeshElement* elem = elemIt->next();
+    if(elem->GetType() == SMDSAbs_0DElement)
+      continue;
+    
     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
     if ( elem->GetType() == SMDSAbs_Volume )
     {
@@ -6241,7 +6244,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
     const SMDS_MeshNode* closestNode = 0;
     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
     for ( ; nIt != nodes.end(); ++nIt ) {
-      double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
+      double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
       if ( minSqDist > sqDist ) {
         closestNode = *nIt;
         minSqDist = sqDist;
@@ -6296,7 +6299,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
   {
   public:
 
-    ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius );
+    ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
     ~ElementBndBoxTree();
@@ -6323,13 +6326,13 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
    */
   //================================================================================
 
-  ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance)
+  ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
   {
     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
     _elements.reserve( nbElems );
 
-    SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
+    SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
     while ( elemIt->more() )
       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
 
@@ -6461,7 +6464,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
     _refCount = 1;
     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
     while ( nIt->more() )
-      Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
+      Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
     Enlarge( tolerance );
   }
 
@@ -6477,6 +6480,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
 {
   SMESHDS_Mesh*                _mesh;
+  SMDS_ElemIteratorPtr         _meshPartIt;
   ElementBndBoxTree*           _ebbTree;
   SMESH_NodeSearcherImpl*      _nodeSearcher;
   SMDSAbs_ElementType          _elementType;
@@ -6484,8 +6488,8 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
   bool                         _outerFacesFound;
   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
 
-  SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
-    : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
+  SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
+    : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
   ~SMESH_ElementSearcherImpl()
   {
     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
@@ -6567,7 +6571,7 @@ double SMESH_ElementSearcherImpl::getTolerance()
         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
         elemSize = 1;
         if ( meshInfo.NbNodes() > 2 )
-          elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
+          elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
       }
       else
       {
@@ -6575,7 +6579,8 @@ double SMESH_ElementSearcherImpl::getTolerance()
             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
         const SMDS_MeshElement* elem = elemIt->next();
         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
-        SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
+        SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
+        elemSize = 0;
         while ( nodeIt->more() )
         {
           double dist = n1.Distance( cast2Node( nodeIt->next() ));
@@ -6608,8 +6613,8 @@ bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           lin
   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
   {
-    GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
-                         SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
+    GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
+                         SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
     anExtCC.Init( lineCurve, edge);
     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
     {
@@ -6669,8 +6674,8 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF
       seamLinks.insert( link );
 
       // link direction within the outerFace
-      gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
-                   SMESH_MeshEditor::TNodeXYZ( link.node2()));
+      gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
+                   SMESH_TNodeXYZ( link.node2()));
       int i1 = outerFace->GetNodeIndex( link.node1() );
       int i2 = outerFace->GetNodeIndex( link.node2() );
       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
@@ -6753,7 +6758,7 @@ FindElementsByPoint(const gp_Pnt&                      point,
     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
     if ( !closeNode ) return foundElements.size();
 
-    if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
+    if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
       return foundElements.size(); // to far from any node
 
     if ( type == SMDSAbs_Node )
@@ -6773,7 +6778,7 @@ FindElementsByPoint(const gp_Pnt&                      point,
     if ( !_ebbTree || _elementType != type )
     {
       if ( _ebbTree ) delete _ebbTree;
-      _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance );
+      _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
     }
     TIDSortedElemSet suspectElems;
     _ebbTree->getElementsNearPoint( point, suspectElems );
@@ -6797,7 +6802,7 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
   if ( !_ebbTree || _elementType != SMDSAbs_Face )
   {
     if ( _ebbTree ) delete _ebbTree;
-    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
+    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
   }
   // Algo: analyse transition of a line starting at the point through mesh boundary;
   // try three lines parallel to axis of the coordinate system and perform rough
@@ -6825,7 +6830,7 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
       // get face plane
       gp_XYZ fNorm;
       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
-      gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
+      gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
 
       // perform intersection
       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
@@ -7021,7 +7026,7 @@ void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&
   if ( !_ebbTree || _elementType != type )
   {
     if ( _ebbTree ) delete _ebbTree;
-    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
+    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
   }
   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
   _ebbTree->getElementsNearLine( line, suspectFaces );
@@ -7039,6 +7044,17 @@ SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
 }
 
+//=======================================================================
+/*!
+ * \brief Return SMESH_ElementSearcher
+ */
+//=======================================================================
+
+SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
+{
+  return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
+}
+
 //=======================================================================
 /*!
  * \brief Return true if the point is IN or ON of the element
@@ -7067,7 +7083,7 @@ bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& poi
   while ( nodeIt->more() )
     {
       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
-      xyz.push_back( TNodeXYZ(node) );
+      xyz.push_back( SMESH_TNodeXYZ(node) );
       nodeList.push_back(node);
     }
 
@@ -10481,7 +10497,7 @@ namespace {
     gp_XYZ centerXYZ (0, 0, 0);
     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
     while (aNodeItr->more())
-      centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
+      centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
 
     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
     theClassifier.Perform(aPnt, theTol);
@@ -10600,9 +10616,9 @@ bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
                                                      bool createJointElems)
 {
-  MESSAGE("------------------------------------------------------");
-  MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
-  MESSAGE("------------------------------------------------------");
+  MESSAGE("----------------------------------------------");
+  MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
+  MESSAGE("----------------------------------------------");
 
   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
   meshDS->BuildDownWardConnectivity(false);
@@ -10610,11 +10626,16 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
 
   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
+  //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
   //     build the list of nodes shared by 2 or more domains, with their domain indexes
 
-  std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
-  std::map<int, std::map<int,int> > nodeDomains; //oldId ->  (domainId -> newId)
+  std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
+  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;
   emptyMap.clear();
@@ -10651,6 +10672,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
                   if (!faceDomains[face].count(idom))
                     {
                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
+                      celldom[vtkId] = idom;
                     }
                 }
             }
@@ -10658,36 +10680,91 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
     }
 
   MESSAGE("Number of shared faces " << faceDomains.size());
+  std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
+
+  // --- explore the shared faces domain by domain,
+  //     explore the nodes of the face and see if they belong to a cell in the domain,
+  //     which has only a node or an edge on the border (not a shared face)
 
-  // --- for each shared face, get the nodes
+  for (int idomain = 0; idomain < theElems.size(); idomain++)
+    {
+      const TIDSortedElemSet& domain = theElems[idomain];
+      itface = faceDomains.begin();
+      for (; itface != faceDomains.end(); ++itface)
+        {
+          std::map<int, int> domvol = itface->second;
+          if (!domvol.count(idomain))
+            continue;
+          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)
+            {
+              int oldId = *itn;
+              //MESSAGE("     node " << oldId);
+              std::set<int> cells;
+              cells.clear();
+              vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
+              for (int i=0; i<l.ncells; i++)
+                {
+                  int vtkId = l.cells[i];
+                  const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
+                  if (!domain.count(anElem))
+                    continue;
+                  int vtkType = grid->GetCellType(vtkId);
+                  int downId = grid->CellIdToDownId(vtkId);
+                  DownIdType aCell(downId, vtkType);
+                  if (celldom.count(vtkId))
+                    continue;
+                  cellDomains[aCell][idomain] = vtkId;
+                  celldom[vtkId] = idomain;
+                }
+            }
+        }
+    }
+
+  // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
+  //     for each shared face, get the nodes
   //     for each node, for each domain of the face, create a clone of the node
 
-  std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
-  for( ; itface != faceDomains.end();++itface )
+  for (int idomain = 0; idomain < theElems.size(); idomain++)
     {
-      DownIdType face = itface->first;
-      std::map<int,int> domvol = itface->second;
-      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)
+      itface = faceDomains.begin();
+      for (; itface != faceDomains.end(); ++itface)
         {
-          int oldId = *itn;
-          if (!nodeDomains.count(oldId))
-            nodeDomains[oldId] = emptyMap; // create an empty entry for node
-          std::map<int,int>::iterator itdom = domvol.begin();
-          for(; itdom != domvol.end(); ++itdom)
+          std::map<int, int> domvol = itface->second;
+          if (!domvol.count(idomain))
+            continue;
+          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)
             {
-              int idom = itdom->first;
-              if ( nodeDomains[oldId].empty() )
-                nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
-              else
+              int oldId = *itn;
+              //MESSAGE("     node " << oldId);
+              if (!nodeDomains.count(oldId))
+                nodeDomains[oldId] = emptyMap; // create an empty entry for node
+              if (nodeDomains[oldId].empty())
+                nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
+              std::map<int, int>::iterator itdom = domvol.begin();
+              for (; itdom != domvol.end(); ++itdom)
                 {
-                  double *coords = grid->GetPoint(oldId);
-                  SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
-                  int newId = newNode->getVtkId();
-                  nodeDomains[oldId][idom] = newId; // cloned node for other domains
+                  int idom = itdom->first;
+                  //MESSAGE("         domain " << idom);
+                  if (!nodeDomains[oldId].count(idom))
+                    {
+                      double *coords = grid->GetPoint(oldId);
+                      SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
+                      int newId = newNode->getVtkId();
+                      nodeDomains[oldId][idom] = newId; // cloned node for other domains
+                      //MESSAGE("         newNode " << newId);
+                    }
                 }
             }
         }
@@ -10697,6 +10774,10 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
   //     get node id's of the face (id SMDS = id VTK)
   //     create flat element with old and new nodes if requested
 
+  // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
+  //     (domain1 X domain2) = domain1 + MAXINT*domain2
+  std::map<int, std::map<long,int> > nodeQuadDomains;
+
   if (createJointElems)
     {
       itface = faceDomains.begin();
@@ -10707,7 +10788,6 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
           std::set<int>::iterator itn;
           oldNodes.clear();
           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
-          std::map<int,int> localClonedNodeIds;
 
           std::map<int,int> domvol = itface->second;
           std::map<int,int>::iterator itdom = domvol.begin();
@@ -10715,24 +10795,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
           int vtkVolId = itdom->second;
           itdom++;
           int dom2 = itdom->first;
-
-          localClonedNodeIds.clear();
-          for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
-            {
-              int oldId = *itn;
-              int refid = oldId;
-              if (nodeDomains[oldId].count(dom1))
-                refid = nodeDomains[oldId][dom1];
-              else
-                MESSAGE("--- problem domain node " << dom1 << " " << oldId);
-              int newid = oldId;
-              if (nodeDomains[oldId].count(dom2))
-                newid = nodeDomains[oldId][dom2];
-              else
-                MESSAGE("--- problem domain node " << dom2 << " " << oldId);
-              localClonedNodeIds[oldId] = newid;
-            }
-          meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
+          grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains, nodeQuadDomains);
         }
     }
 
@@ -10740,6 +10803,8 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
   //     get node id's of the face
   //     replace old nodes by new nodes in volumes, and update inverse connectivity
 
+  MESSAGE("cellDomains " << cellDomains.size());
+  faceDomains.insert(cellDomains.begin(), cellDomains.end());
   itface = faceDomains.begin();
   for( ; itface != faceDomains.end();++itface )
     {
@@ -10844,15 +10909,23 @@ namespace
  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
  *                                boundary elements will be copied into the targetMesh
+ *  \param toAddExistingBondary - if true, not only new but also pre-existing
+ *                                boundary elements will be added into the new group
+ *  \param aroundElements - if true, elements will be created on boundary of given
+ *                          elements else, on boundary of the whole mesh. This
+ *                          option works for 2D elements only.
+ * \return nb of added boundary elements
  */
 //================================================================================
 
-void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
-                                        Bnd_Dimension           dimension,
-                                        SMESH_Group*            group/*=0*/,
-                                        SMESH_Mesh*             targetMesh/*=0*/,
-                                        bool                    toCopyElements/*=false*/,
-                                        bool                    toCopyExistingBondary/*=false*/)
+int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
+                                       Bnd_Dimension           dimension,
+                                       SMESH_Group*            group/*=0*/,
+                                       SMESH_Mesh*             targetMesh/*=0*/,
+                                       bool                    toCopyElements/*=false*/,
+                                       bool                    toCopyExistingBondary/*=false*/,
+                                       bool                    toAddExistingBondary/*= false*/,
+                                       bool                    aroundElements/*= false*/)
 {
   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
@@ -10860,14 +10933,24 @@ void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
     throw SALOME_Exception(LOCALIZED("wrong element type"));
 
+  if ( aroundElements && elemType == SMDSAbs_Volume )
+    throw SALOME_Exception(LOCALIZED("wrong element type for aroundElements==true"));
+
   if ( !targetMesh )
     toCopyElements = toCopyExistingBondary = false;
 
   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
+  int nbAddedBnd = 0;
+
+  // editor adding present bnd elements and optionally holding elements to add to the group
+  SMESH_MeshEditor* presentEditor;
+  SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
+  presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
 
   SMDS_VolumeTool vTool;
-  TIDSortedElemSet emptySet, avoidSet;
+  TIDSortedElemSet avoidSet;
+  const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
   int inode;
 
   typedef vector<const SMDS_MeshNode*> TConnectivity;
@@ -10883,7 +10966,9 @@ void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
     const SMDS_MeshElement* elem = eIt->next();
     const int iQuad = elem->IsQuadratic();
 
+    // ------------------------------------------------------------------------------------
     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
+    // ------------------------------------------------------------------------------------
     vector<const SMDS_MeshElement*> presentBndElems;
     vector<TConnectivity>           missingBndElems;
     TConnectivity nodes;
@@ -10935,7 +11020,7 @@ void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
       {
         nodes[0] = elem->GetNode(i);
         nodes[1] = elem->GetNode((i+1)%nbNodes);
-        if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
+        if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
           continue; // not free link
 
         //if ( iQuad )
@@ -10948,7 +11033,9 @@ void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
       }
     }
 
+    // ---------------------------------
     // 2. Add missing boundary elements
+    // ---------------------------------
     if ( targetMesh != myMesh )
       // instead of making a map of nodes in this mesh and targetMesh,
       // we create nodes with same IDs. We can renumber them later, if needed
@@ -10958,16 +11045,28 @@ void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
         TConnectivity  nodes( srcNodes.size() );
         for ( inode = 0; inode < nodes.size(); ++inode )
           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
+        if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
+                                                                   missType,
+                                                                   /*noMedium=*/true))
+          continue;
         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
+        ++nbAddedBnd;
       }
     else
       for ( int i = 0; i < missingBndElems.size(); ++i )
       {
-        TConnectivity&  nodes = missingBndElems[i];
+        TConnectivity& nodes = missingBndElems[i];
+        if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
+                                                                   missType,
+                                                                   /*noMedium=*/true))
+          continue;
         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
+        ++nbAddedBnd;
       }
 
+    // ----------------------------------
     // 3. Copy present boundary elements
+    // ----------------------------------
     if ( toCopyExistingBondary )
       for ( int i = 0 ; i < presentBndElems.size(); ++i )
       {
@@ -10975,13 +11074,19 @@ void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
         TConnectivity nodes( e->NbNodes() );
         for ( inode = 0; inode < nodes.size(); ++inode )
           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
-        tgtEditor.AddElement(nodes, missType, e->IsPoly());
-        // leave only missing elements in tgtEditor.myLastCreatedElems
-        tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
+        presentEditor->AddElement(nodes, missType, e->IsPoly());
+      }
+    else // store present elements to add them to a group
+      for ( int i = 0 ; i < presentBndElems.size(); ++i )
+      {
+        presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
       }
+      
   } // loop on given elements
 
-  // 4. Fill group with missing boundary elements
+  // ---------------------------------------------
+  // 4. Fill group with boundary elements
+  // ---------------------------------------------
   if ( group )
   {
     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
@@ -10989,9 +11094,12 @@ void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
   }
   tgtEditor.myLastCreatedElems.Clear();
+  tgtEditor2.myLastCreatedElems.Clear();
 
+  // -----------------------
   // 5. Copy given elements
-  if ( toCopyElements )
+  // -----------------------
+  if ( toCopyElements && targetMesh != myMesh )
   {
     if (elements.empty())
       eIt = aMesh->elementsIterator(elemType);
@@ -11008,5 +11116,5 @@ void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
       tgtEditor.myLastCreatedElems.Clear();
     }
   }
-  return;
+  return nbAddedBnd;
 }