Salome HOME
23256: [CEA 1796] Merge nodes suppresses some elements
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
index e54f0184660f384397276e55e23a8a6ae4cbc454..a37950e411a9a58af2f95936f903fcfbbc46bed2 100644 (file)
@@ -7215,76 +7215,52 @@ int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *>& faceNod
                                     vector<int>&                         quantities) const
 {
   int nbNodes = faceNodes.size();
-
-  if (nbNodes < 3)
+  while ( faceNodes[ 0 ] == faceNodes[ nbNodes-1 ] && nbNodes > 2 )
+    --nbNodes;
+  if ( nbNodes < 3 )
     return 0;
+  size_t prevNbQuant = quantities.size();
 
-  set<const SMDS_MeshNode*> nodeSet;
-
-  // get simple seq of nodes
-  vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
-  int iSimple = 0;
-
-  simpleNodes[iSimple++] = faceNodes[0];
-  for (int iCur = 1; iCur < nbNodes; iCur++) {
-    if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
-      simpleNodes[iSimple++] = faceNodes[iCur];
-      nodeSet.insert( faceNodes[iCur] );
-    }
-  }
-  int nbUnique = nodeSet.size();
-  int nbSimple = iSimple;
-  if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
-    nbSimple--;
-    iSimple--;
-  }
+  vector< const SMDS_MeshNode* > simpleNodes; simpleNodes.reserve( nbNodes );
+  map< const SMDS_MeshNode*, int > nodeIndices; // indices within simpleNodes
+  map< const SMDS_MeshNode*, int >::iterator nInd;
 
-  if (nbUnique < 3)
-    return 0;
-
-  // separate loops
-  int nbNew = 0;
-  bool foundLoop = (nbSimple > nbUnique);
-  while (foundLoop) {
-    foundLoop = false;
-    set<const SMDS_MeshNode*> loopSet;
-    for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
-      const SMDS_MeshNode* n = simpleNodes[iSimple];
-      if (!loopSet.insert( n ).second) {
-        foundLoop = true;
-
-        // separate loop
-        int iC = 0, curLast = iSimple;
-        for (; iC < curLast; iC++) {
-          if (simpleNodes[iC] == n) break;
-        }
-        int loopLen = curLast - iC;
-        if (loopLen > 2) {
-          // create sub-element
-          nbNew++;
-          quantities.push_back(loopLen);
-          for (; iC < curLast; iC++) {
-            poly_nodes.push_back(simpleNodes[iC]);
-          }
-        }
-        // shift the rest nodes (place from the first loop position)
-        for (iC = curLast + 1; iC < nbSimple; iC++) {
-          simpleNodes[iC - loopLen] = simpleNodes[iC];
+  nodeIndices.insert( make_pair( faceNodes[0], 0 ));
+  simpleNodes.push_back( faceNodes[0] );
+  for ( int iCur = 1; iCur < nbNodes; iCur++ )
+  {
+    if ( faceNodes[ iCur ] != simpleNodes.back() )
+    {
+      int index = simpleNodes.size();
+      nInd = nodeIndices.insert( make_pair( faceNodes[ iCur ], index )).first;
+      int prevIndex = nInd->second;
+      if ( prevIndex < index )
+      {
+        // a sub-loop found
+        int loopLen = index - prevIndex;
+        if ( loopLen > 2 )
+        {
+          // store the sub-loop
+          quantities.push_back( loopLen );
+          for ( int i = prevIndex; i < index; i++ )
+            poly_nodes.push_back( simpleNodes[ i ]);
         }
-        nbSimple -= loopLen;
-        iSimple -= loopLen;
+        simpleNodes.resize( prevIndex+1 );
       }
-    } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
-  } // while (foundLoop)
+      else
+      {
+        simpleNodes.push_back( faceNodes[ iCur ]);
+      }
+    }
+  }
 
-  if (iSimple > 2) {
-    nbNew++;
-    quantities.push_back(iSimple);
-    for (int i = 0; i < iSimple; i++)
-      poly_nodes.push_back(simpleNodes[i]);
+  if ( simpleNodes.size() > 2 )
+  {
+    quantities.push_back( simpleNodes.size() );
+    poly_nodes.insert ( poly_nodes.end(), simpleNodes.begin(), simpleNodes.end() );
   }
 
-  return nbNew;
+  return quantities.size() - prevNbQuant;
 }
 
 //=======================================================================
@@ -7348,6 +7324,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
     const SMDS_MeshElement* elem = *eIt;
     const           int  nbNodes = elem->NbNodes();
     const           int aShapeId = FindShape( elem );
+    SMDSAbs_EntityType    entity = elem->GetEntityType();
 
     nodeSet.clear();
     curNodes.resize( nbNodes );
@@ -7373,7 +7350,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
               n = (*nnIt_i).second;
               if (!nodesRecur.insert(n).second) {
-                // error: recursive dependancy
+                // error: recursive dependency
                 stopRecur = true;
               }
             }
@@ -7397,9 +7374,9 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
     int nbUniqueNodes = nodeSet.size();
     if ( nbNodes != nbUniqueNodes ) // some nodes stick
     {
-      if (elem->IsPoly()) // Polygons and Polyhedral volumes
+      if ( elem->IsPoly() ) // Polygons and Polyhedral volumes
       {
-        if (elem->GetType() == SMDSAbs_Face) // Polygon
+        if ( elem->GetType() == SMDSAbs_Face ) // Polygon
         {
           elemType.Init( elem );
           const bool isQuad = elemType.myIsQuad;
@@ -7434,7 +7411,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
               }
               elemType.SetPoly(( nbNewNodes / ( elemType.myIsQuad + 1 ) > 4 ));
 
-              SMDS_MeshElement* newElem = AddElement( face_nodes, elemType );
+              SMDS_MeshElement* newElem = AddElement( face_nodes, elemType.SetID(-1));
               if ( aShapeId )
                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
             }
@@ -7443,53 +7420,53 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 
         } // Polygon
 
-        else if (elem->GetType() == SMDSAbs_Volume) // Polyhedral volume
+        else if ( elem->GetType() == SMDSAbs_Volume ) // Polyhedral volume
         {
-          if (nbUniqueNodes < 4) {
+          if ( nbUniqueNodes < 4 ) {
             rmElemIds.push_back(elem->GetID());
           }
           else {
             // each face has to be analyzed in order to check volume validity
             const SMDS_VtkVolume* aPolyedre = dynamic_cast<const SMDS_VtkVolume*>( elem );
-            if (aPolyedre)
+            if ( aPolyedre )
             {
               int nbFaces = aPolyedre->NbFaces();
 
               vector<const SMDS_MeshNode *> poly_nodes;
-              vector<int> quantities;
+              vector<int>                   quantities;
+              vector<const SMDS_MeshNode *> faceNodes;
 
-              for (int iface = 1; iface <= nbFaces; iface++) {
+              for (int iface = 1; iface <= nbFaces; iface++)
+              {
                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
-                vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
-
-                for (int inode = 1; inode <= nbFaceNodes; inode++) {
+                faceNodes.resize( nbFaceNodes );
+                for (int inode = 1; inode <= nbFaceNodes; inode++)
+                {
                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
-                  if (nnIt != nodeNodeMap.end()) { // faceNode sticks
+                  if ( nnIt != nodeNodeMap.end() ) // faceNode sticks
                     faceNode = (*nnIt).second;
-                  }
                   faceNodes[inode - 1] = faceNode;
                 }
-
                 SimplifyFace(faceNodes, poly_nodes, quantities);
               }
 
-              if (quantities.size() > 3) {
-                // to be done: remove coincident faces
+              if ( quantities.size() > 3 ) {
+                // TODO: remove coincident faces
               }
 
-              if (quantities.size() > 3)
+              if ( quantities.size() > 3 )
               {
                 const SMDS_MeshElement* newElem =
-                  aMesh->AddPolyhedralVolume(poly_nodes, quantities);
-                myLastCreatedElems.Append(newElem);
+                  aMesh->AddPolyhedralVolume( poly_nodes, quantities );
+                myLastCreatedElems.Append( newElem );
                 if ( aShapeId && newElem )
                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
-                rmElemIds.push_back(elem->GetID());
+                rmElemIds.push_back( elem->GetID() );
               }
             }
             else {
-              rmElemIds.push_back(elem->GetID());
+              rmElemIds.push_back( elem->GetID() );
             }
           }
         }
@@ -7501,195 +7478,154 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 
       // Regular elements
       // TODO not all the possible cases are solved. Find something more generic?
-      switch ( nbNodes ) {
-      case 2: ///////////////////////////////////// EDGE
-        isOk = false; break;
-      case 3: ///////////////////////////////////// TRIANGLE
-        isOk = false; break;
-      case 4:
-        if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
+      switch ( entity ) {
+      case SMDSEntity_Edge: //////// EDGE
+      case SMDSEntity_Triangle: //// TRIANGLE
+      case SMDSEntity_Quad_Triangle:
+      case SMDSEntity_Tetra:
+      case SMDSEntity_Quad_Tetra: // TETRAHEDRON
+      {
+        isOk = false;
+        break;
+      }
+      case SMDSEntity_Quad_Edge:
+      {
+        isOk = false; // to linear EDGE ???????
+        break;
+      }
+      case SMDSEntity_Quadrangle: //////////////////////////////////// QUADRANGLE
+      {
+        if ( nbUniqueNodes < 3 )
           isOk = false;
-        else { //////////////////////////////////// QUADRANGLE
-          if ( nbUniqueNodes < 3 )
-            isOk = false;
-          else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
-            isOk = false; // opposite nodes stick
-          //MESSAGE("isOk " << isOk);
+        else if ( nbRepl == 1 && curNodes[ iRepl[0]] == curNodes[( iRepl[0]+2 )%4 ])
+          isOk = false; // opposite nodes stick
+        break;
+      }
+      case SMDSEntity_Quad_Quadrangle: // Quadratic QUADRANGLE
+      {
+        //   1    5    2
+        //    +---+---+
+        //    |       |
+        //   4+       +6
+        //    |       |
+        //    +---+---+
+        //   0    7    3
+        if (( nbUniqueNodes == 6 && nbRepl == 2 ) &&
+            (( iRepl[0] == 1 && iRepl[1] == 4 && curNodes[1] == curNodes[0] ) ||
+             ( iRepl[0] == 2 && iRepl[1] == 5 && curNodes[2] == curNodes[1] ) ||
+             ( iRepl[0] == 3 && iRepl[1] == 6 && curNodes[3] == curNodes[2] ) ||
+             ( iRepl[0] == 3 && iRepl[1] == 7 && curNodes[3] == curNodes[0] )))
+        {
+          isOk = true;
         }
         break;
-      case 6: ///////////////////////////////////// PENTAHEDRON
+      }
+      case SMDSEntity_BiQuad_Quadrangle: // Bi-Quadratic QUADRANGLE
+      {
+        //   1    5    2
+        //    +---+---+
+        //    |       |
+        //   4+  8+   +6
+        //    |       |
+        //    +---+---+
+        //   0    7    3
+        if (( nbUniqueNodes == 7 && nbRepl == 2 && iRepl[1] != 8 ) &&
+            (( iRepl[0] == 1 && iRepl[1] == 4 && curNodes[1] == curNodes[0] ) ||
+             ( iRepl[0] == 2 && iRepl[1] == 5 && curNodes[2] == curNodes[1] ) ||
+             ( iRepl[0] == 3 && iRepl[1] == 6 && curNodes[3] == curNodes[2] ) ||
+             ( iRepl[0] == 3 && iRepl[1] == 7 && curNodes[3] == curNodes[0] )))
+        {
+          isOk = true;
+        }
+        break;
+      }
+      case SMDSEntity_Penta: ///////////////////////////////////// PENTAHEDRON
+      {
+        isOk = false;
         if ( nbUniqueNodes == 4 ) {
           // ---------------------------------> tetrahedron
-          if (nbRepl == 3 &&
-              iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
-            // all top nodes stick: reverse a bottom
-            uniqueNodes[ 0 ] = curNodes [ 1 ];
-            uniqueNodes[ 1 ] = curNodes [ 0 ];
+          if ( curNodes[3] == curNodes[4] &&
+               curNodes[3] == curNodes[5] ) {
+            // top nodes stick
+            isOk = true;
           }
-          else if (nbRepl == 3 &&
-                   iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
-            // all bottom nodes stick: set a top before
+          else if ( curNodes[0] == curNodes[1] &&
+                    curNodes[0] == curNodes[2] ) {
+            // bottom nodes stick: set a top before
             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
-            uniqueNodes[ 0 ] = curNodes [ 3 ];
+            uniqueNodes[ 0 ] = curNodes [ 5 ];
             uniqueNodes[ 1 ] = curNodes [ 4 ];
-            uniqueNodes[ 2 ] = curNodes [ 5 ];
+            uniqueNodes[ 2 ] = curNodes [ 3 ];
+            isOk = true;
           }
-          else if (nbRepl == 4 &&
-                   iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
-            // a lateral face turns into a line: reverse a bottom
-            uniqueNodes[ 0 ] = curNodes [ 1 ];
-            uniqueNodes[ 1 ] = curNodes [ 0 ];
+          else if (( curNodes[0] == curNodes[3] ) +
+                   ( curNodes[1] == curNodes[4] ) +
+                   ( curNodes[2] == curNodes[5] ) == 2 ) {
+            // a lateral face turns into a line
+            isOk = true;
           }
-          else
-            isOk = false;
         }
         else if ( nbUniqueNodes == 5 ) {
-          // PENTAHEDRON --------------------> 2 tetrahedrons
-          if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
-            // a bottom node sticks with a linked top one
-            // 1.
-            SMDS_MeshElement* newElem =
-              aMesh->AddVolume(curNodes[ 3 ],
-                               curNodes[ 4 ],
-                               curNodes[ 5 ],
-                               curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
-            myLastCreatedElems.Append(newElem);
-            if ( aShapeId )
-              aMesh->SetMeshElementOnShape( newElem, aShapeId );
-            // 2. : reverse a bottom
-            uniqueNodes[ 0 ] = curNodes [ 1 ];
-            uniqueNodes[ 1 ] = curNodes [ 0 ];
-            nbUniqueNodes = 4;
-          }
-          else
-            isOk = false;
-        }
-        else
-          isOk = false;
-        break;
-      case 8: {
-        if(elem->IsQuadratic()) { // Quadratic quadrangle
-          //   1    5    2
-          //    +---+---+
-          //    |       |
-          //    |       |
-          //   4+       +6
-          //    |       |
-          //    |       |
-          //    +---+---+
-          //   0    7    3
-          isOk = false;
-          if(nbRepl==2) {
-            MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
-          }
-          if(nbRepl==3) {
-            MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
-            nbUniqueNodes = 6;
-            if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
-              uniqueNodes[0] = curNodes[0];
-              uniqueNodes[1] = curNodes[2];
-              uniqueNodes[2] = curNodes[3];
-              uniqueNodes[3] = curNodes[5];
-              uniqueNodes[4] = curNodes[6];
-              uniqueNodes[5] = curNodes[7];
-              isOk = true;
-            }
-            if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
-              uniqueNodes[0] = curNodes[0];
-              uniqueNodes[1] = curNodes[1];
-              uniqueNodes[2] = curNodes[2];
-              uniqueNodes[3] = curNodes[4];
-              uniqueNodes[4] = curNodes[5];
-              uniqueNodes[5] = curNodes[6];
-              isOk = true;
-            }
-            if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
-              uniqueNodes[0] = curNodes[1];
-              uniqueNodes[1] = curNodes[2];
-              uniqueNodes[2] = curNodes[3];
-              uniqueNodes[3] = curNodes[5];
-              uniqueNodes[4] = curNodes[6];
-              uniqueNodes[5] = curNodes[0];
-              isOk = true;
-            }
-            if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
-              uniqueNodes[0] = curNodes[0];
-              uniqueNodes[1] = curNodes[1];
-              uniqueNodes[2] = curNodes[3];
-              uniqueNodes[3] = curNodes[4];
-              uniqueNodes[4] = curNodes[6];
-              uniqueNodes[5] = curNodes[7];
-              isOk = true;
-            }
-            if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
-              uniqueNodes[0] = curNodes[0];
-              uniqueNodes[1] = curNodes[2];
-              uniqueNodes[2] = curNodes[3];
-              uniqueNodes[3] = curNodes[1];
-              uniqueNodes[4] = curNodes[6];
-              uniqueNodes[5] = curNodes[7];
-              isOk = true;
-            }
-            if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
-              uniqueNodes[0] = curNodes[0];
-              uniqueNodes[1] = curNodes[1];
-              uniqueNodes[2] = curNodes[2];
-              uniqueNodes[3] = curNodes[4];
-              uniqueNodes[4] = curNodes[5];
-              uniqueNodes[5] = curNodes[7];
-              isOk = true;
-            }
-            if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
-              uniqueNodes[0] = curNodes[0];
-              uniqueNodes[1] = curNodes[1];
-              uniqueNodes[2] = curNodes[3];
-              uniqueNodes[3] = curNodes[4];
-              uniqueNodes[4] = curNodes[2];
-              uniqueNodes[5] = curNodes[7];
-              isOk = true;
-            }
-            if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
-              uniqueNodes[0] = curNodes[0];
-              uniqueNodes[1] = curNodes[1];
-              uniqueNodes[2] = curNodes[2];
-              uniqueNodes[3] = curNodes[4];
-              uniqueNodes[4] = curNodes[5];
-              uniqueNodes[5] = curNodes[3];
-              isOk = true;
-            }
+          // PENTAHEDRON --------------------> pyramid
+          if ( curNodes[0] == curNodes[3] )
+          {
+            uniqueNodes[ 0 ] = curNodes[ 1 ];
+            uniqueNodes[ 1 ] = curNodes[ 4 ];
+            uniqueNodes[ 2 ] = curNodes[ 5 ];
+            uniqueNodes[ 3 ] = curNodes[ 2 ];
+            uniqueNodes[ 4 ] = curNodes[ 0 ];
+            isOk = true;
           }
-          if(nbRepl==4) {
-            MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
+          if ( curNodes[1] == curNodes[4] )
+          {
+            uniqueNodes[ 0 ] = curNodes[ 0 ];
+            uniqueNodes[ 1 ] = curNodes[ 2 ];
+            uniqueNodes[ 2 ] = curNodes[ 5 ];
+            uniqueNodes[ 3 ] = curNodes[ 3 ];
+            uniqueNodes[ 4 ] = curNodes[ 1 ];
+            isOk = true;
           }
-          if(nbRepl==5) {
-            MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
+          if ( curNodes[2] == curNodes[5] )
+          {
+            uniqueNodes[ 0 ] = curNodes[ 0 ];
+            uniqueNodes[ 1 ] = curNodes[ 3 ];
+            uniqueNodes[ 2 ] = curNodes[ 4 ];
+            uniqueNodes[ 3 ] = curNodes[ 1 ];
+            uniqueNodes[ 4 ] = curNodes[ 2 ];
+            isOk = true;
           }
-          break;
         }
+        break;
+      }
+      case SMDSEntity_Hexa:
+      {
         //////////////////////////////////// HEXAHEDRON
         isOk = false;
         SMDS_VolumeTool hexa (elem);
         hexa.SetExternalNormal();
         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
-          //////////////////////// HEX ---> tetrahedron
+          //////////////////////// HEX ---> tetrahedron
           for ( int iFace = 0; iFace < 6; iFace++ ) {
             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
               // one face turns into a point ...
+              int  pickInd = ind[ 0 ];
               int iOppFace = hexa.GetOppFaceIndex( iFace );
               ind = hexa.GetFaceNodesIndices( iOppFace );
               int nbStick = 0;
+              uniqueNodes.clear();
               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
                   nbStick++;
+                else
+                  uniqueNodes.push_back( curNodes[ind[ iCur ]]);
               }
               if ( nbStick == 1 ) {
                 // ... and the opposite one - into a triangle.
                 // set a top node
-                ind = hexa.GetFaceNodesIndices( iFace );
-                uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
+                uniqueNodes.push_back( curNodes[ pickInd ]);
                 isOk = true;
               }
               break;
@@ -7697,7 +7633,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
           }
         }
         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
-          //////////////////////// HEX ---> prism
+          //////////////////////// HEX ---> prism
           int nbTria = 0, iTria[3];
           const int *ind; // indices of face nodes
           // look for triangular faces
@@ -7712,7 +7648,6 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
           // check if triangles are opposite
           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
           {
-            isOk = true;
             // set nodes of the bottom triangle
             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
             vector<int> indB;
@@ -7732,11 +7667,12 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
                   break;
                 }
+            isOk = true;
+            break;
           }
-          break;
         }
-        else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
-          //////////////////// HEXAHEDRON ---> 2 tetrahedrons
+        else if (nbUniqueNodes == 5 && nbRepl == 3 ) {
+          //////////////////// HEXAHEDRON ---> pyramid
           for ( int iFace = 0; iFace < 6; iFace++ ) {
             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
@@ -7745,139 +7681,61 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
               // one face turns into a point ...
               int iOppFace = hexa.GetOppFaceIndex( iFace );
               ind = hexa.GetFaceNodesIndices( iOppFace );
-              int nbStick = 0;
-              iUnique = 2;  // reverse a tetrahedron 1 bottom
-              for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
+              uniqueNodes.clear();
+              for ( iCur = 0; iCur < 4; iCur++ ) {
                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
-                  nbStick++;
-                else if ( iUnique >= 0 )
-                  uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
+                  break;
+                else
+                  uniqueNodes.push_back( curNodes[ind[ iCur ]]);
               }
-              if ( nbStick == 0 ) {
+              if ( uniqueNodes.size() == 4 ) {
                 // ... and the opposite one is a quadrangle
                 // set a top node
                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
-                uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
-                nbUniqueNodes = 4;
-                // tetrahedron 2
-                SMDS_MeshElement* newElem =
-                  aMesh->AddVolume(curNodes[ind[ 0 ]],
-                                   curNodes[ind[ 3 ]],
-                                   curNodes[ind[ 2 ]],
-                                   curNodes[indTop[ 0 ]]);
-                myLastCreatedElems.Append(newElem);
-                if ( aShapeId )
-                  aMesh->SetMeshElementOnShape( newElem, aShapeId );
+                uniqueNodes.push_back( curNodes[indTop[ 0 ]]);
                 isOk = true;
               }
               break;
             }
           }
         }
-        else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
-          ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
-          // find indices of quad and tri faces
-          int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
-          for ( iFace = 0; iFace < 6; iFace++ ) {
+
+        if ( !isOk && nbUniqueNodes > 4 ) {
+          ////////////////// HEXAHEDRON ---> polyhedron
+          hexa.SetExternalNormal();
+          vector<const SMDS_MeshNode *> poly_nodes; poly_nodes.reserve( 6 * 4 );
+          vector<int>                   quantities; quantities.reserve( 6 );
+          for ( int iFace = 0; iFace < 6; iFace++ )
+          {
             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
+            if ( curNodes[ind[0]] == curNodes[ind[2]] ||
+                 curNodes[ind[1]] == curNodes[ind[3]] )
+            {
+              quantities.clear();
+              break; // opposite nodes stick
+            }
             nodeSet.clear();
             for ( iCur = 0; iCur < 4; iCur++ )
-              nodeSet.insert( curNodes[ind[ iCur ]] );
-            nbUniqueNodes = nodeSet.size();
-            if ( nbUniqueNodes == 3 )
-              iTriFace[ nbTri++ ] = iFace;
-            else if ( nbUniqueNodes == 4 )
-              iQuadFace[ nbQuad++ ] = iFace;
-          }
-          if (nbQuad == 2 && nbTri == 4 &&
-              hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
-            // 2 opposite quadrangles stuck with a diagonal;
-            // sample groups of merged indices: (0-4)(2-6)
-            // --------------------------------------------> 2 tetrahedrons
-            const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
-            const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
-            int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
-            if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
-                curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
-              // stuck with 0-2 diagonal
-              i0  = ind1[ 3 ];
-              i1d = ind1[ 0 ];
-              i2  = ind1[ 1 ];
-              i3d = ind1[ 2 ];
-              i0t = ind2[ 1 ];
-              i2t = ind2[ 3 ];
-            }
-            else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
-                     curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
-              // stuck with 1-3 diagonal
-              i0  = ind1[ 0 ];
-              i1d = ind1[ 1 ];
-              i2  = ind1[ 2 ];
-              i3d = ind1[ 3 ];
-              i0t = ind2[ 0 ];
-              i2t = ind2[ 1 ];
-            }
-            else {
-              ASSERT(0);
+            {
+              if ( nodeSet.insert( curNodes[ind[ iCur ]] ).second )
+                poly_nodes.push_back( curNodes[ind[ iCur ]]);
             }
-            // tetrahedron 1
-            uniqueNodes[ 0 ] = curNodes [ i0 ];
-            uniqueNodes[ 1 ] = curNodes [ i1d ];
-            uniqueNodes[ 2 ] = curNodes [ i3d ];
-            uniqueNodes[ 3 ] = curNodes [ i0t ];
-            nbUniqueNodes = 4;
-            // tetrahedron 2
-            SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
-                                                         curNodes[ i2 ],
-                                                         curNodes[ i3d ],
-                                                         curNodes[ i2t ]);
-            myLastCreatedElems.Append(newElem);
-            if ( aShapeId )
-              aMesh->SetMeshElementOnShape( newElem, aShapeId );
-            isOk = true;
+            if ( nodeSet.size() < 3 )
+              poly_nodes.resize( poly_nodes.size() - nodeSet.size() );
+            else
+              quantities.push_back( nodeSet.size() );
           }
-          else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
-                   ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
-            // --------------------------------------------> prism
-            // find 2 opposite triangles
-            nbUniqueNodes = 6;
-            for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
-              if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
-                // find indices of kept and replaced nodes
-                // and fill unique nodes of 2 opposite triangles
-                const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
-                const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
-                const SMDS_MeshNode** hexanodes = hexa.GetNodes();
-                // fill unique nodes
-                iUnique = 0;
-                isOk = true;
-                for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
-                  const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
-                  const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
-                  if ( n == nInit ) {
-                    // iCur of a linked node of the opposite face (make normals co-directed):
-                    int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
-                    // check that correspondent corners of triangles are linked
-                    if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
-                      isOk = false;
-                    else {
-                      uniqueNodes[ iUnique ] = n;
-                      uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
-                      iUnique++;
-                    }
-                  }
-                }
-                break;
-              }
-            }
+          if ( quantities.size() >= 4 )
+          {
+            const SMDS_MeshElement* newElem = aMesh->AddPolyhedralVolume( poly_nodes, quantities );
+            myLastCreatedElems.Append( newElem );
+            if ( aShapeId && newElem )
+              aMesh->SetMeshElementOnShape( newElem, aShapeId );
+            rmElemIds.push_back( elem->GetID() );
           }
-        } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
-        else
-        {
-          MESSAGE("MergeNodes() removes hexahedron "<< elem);
         }
         break;
-      } // HEXAHEDRON
+      } // case HEXAHEDRON
 
       default:
         isOk = false;
@@ -7885,7 +7743,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 
     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
 
-    if ( isOk ) // the non-poly elem remains valid after sticking nodes
+    if ( isOk ) // a non-poly elem remains valid after sticking nodes
     {
       if ( nbNodes != nbUniqueNodes ||
            !aMesh->ChangeElementNodes( elem, & curNodes[0], nbNodes ))