Salome HOME
Fix compilation errors under Windows: VS-2017
[modules/smesh.git] / src / StdMeshers / StdMeshers_Hexa_3D.cxx
index 2ac7cafeb43d3559a90c68f8d76c21daad3de73e..eeb6ad40e028aa68d42ff8927e5200cd3752870c 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -20,7 +20,7 @@
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
-//  SMESH SMESH : implementaion of SMESH idl descriptions
+//  SMESH SMESH : implementation of SMESH idl descriptions
 //  File   : StdMeshers_Hexa_3D.cxx
 //           Moved here from SMESH_Hexa_3D.cxx
 //  Author : Paul RASCLE, EDF
 //
 #include "StdMeshers_Hexa_3D.hxx"
 
+#include "SMDS_MeshNode.hxx"
+#include "SMESH_Comment.hxx"
+#include "SMESH_Gen.hxx"
+#include "SMESH_Mesh.hxx"
+#include "SMESH_MesherHelper.hxx"
+#include "SMESH_subMesh.hxx"
+#include "StdMeshers_BlockRenumber.hxx"
 #include "StdMeshers_CompositeHexa_3D.hxx"
 #include "StdMeshers_FaceSide.hxx"
 #include "StdMeshers_HexaFromSkin_3D.hxx"
 #include "StdMeshers_Quadrangle_2D.hxx"
 #include "StdMeshers_ViscousLayers.hxx"
 
-#include "SMESH_Comment.hxx"
-#include "SMESH_Gen.hxx"
-#include "SMESH_Mesh.hxx"
-#include "SMESH_MesherHelper.hxx"
-#include "SMESH_subMesh.hxx"
-
-#include "SMDS_MeshNode.hxx"
-
+#include <BRep_Tool.hxx>
+#include <Bnd_B3d.hxx>
 #include <TopExp.hxx>
 #include <TopExp_Explorer.hxx>
-#include <TopTools_SequenceOfShape.hxx>
 #include <TopTools_MapOfShape.hxx>
+#include <TopTools_SequenceOfShape.hxx>
 #include <TopoDS.hxx>
 
 #include "utilities.h"
 #include "Utils_ExceptHandlers.hxx"
 
+#include <cstddef>
+
+#include <numeric>
+
 typedef SMESH_Comment TComm;
 
 using namespace std;
@@ -70,14 +75,15 @@ static bool EvaluatePentahedralMesh(SMESH_Mesh &, const TopoDS_Shape &,
  */
 //=============================================================================
 
-StdMeshers_Hexa_3D::StdMeshers_Hexa_3D(int hypId, int studyId, SMESH_Gen * gen)
-  :SMESH_3D_Algo(hypId, studyId, gen)
+StdMeshers_Hexa_3D::StdMeshers_Hexa_3D(int hypId, SMESH_Gen * gen)
+  :SMESH_3D_Algo(hypId, gen)
 {
-  MESSAGE("StdMeshers_Hexa_3D::StdMeshers_Hexa_3D");
   _name = "Hexa_3D";
   _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);       // 1 bit /shape type
   _requireShape = false;
   _compatibleHypothesis.push_back("ViscousLayers");
+  _compatibleHypothesis.push_back("BlockRenumber");
+  _quadAlgo = new StdMeshers_Quadrangle_2D( gen->GetANewId(), _gen );
 }
 
 //=============================================================================
@@ -88,7 +94,8 @@ StdMeshers_Hexa_3D::StdMeshers_Hexa_3D(int hypId, int studyId, SMESH_Gen * gen)
 
 StdMeshers_Hexa_3D::~StdMeshers_Hexa_3D()
 {
-  MESSAGE("StdMeshers_Hexa_3D::~StdMeshers_Hexa_3D");
+  delete _quadAlgo;
+  _quadAlgo = 0;
 }
 
 //=============================================================================
@@ -113,7 +120,8 @@ bool StdMeshers_Hexa_3D::CheckHypothesis
     return false;
 */
 
-  _viscousLayersHyp = NULL;
+  _viscousLayersHyp = nullptr;
+  _blockRenumberHyp = nullptr;
 
   const list<const SMESHDS_Hypothesis*>& hyps =
     GetUsedHypothesis(aMesh, aShape, /*ignoreAuxiliary=*/false);
@@ -124,23 +132,29 @@ bool StdMeshers_Hexa_3D::CheckHypothesis
     return true;
   }
 
+  // only StdMeshers_ViscousLayers can be used
   aStatus = HYP_OK;
   for ( ; h != hyps.end(); ++h )
   {
-    string hypName = (*h)->GetName();
-    if ( find( _compatibleHypothesis.begin(),_compatibleHypothesis.end(),hypName )
-         != _compatibleHypothesis.end() )
-    {
-      _viscousLayersHyp = dynamic_cast< const StdMeshers_ViscousLayers*> ( *h );
-    }
-    else
-    {
-      aStatus = HYP_INCOMPATIBLE;
-    }
+    if ( !_viscousLayersHyp &&
+         (_viscousLayersHyp = dynamic_cast< const StdMeshers_ViscousLayers*> ( *h )))
+      continue;
+    if ( !_blockRenumberHyp &&
+         (_blockRenumberHyp = dynamic_cast< const StdMeshers_BlockRenumber*> ( *h )))
+      continue;
+    break;
   }
-
-  if ( !_viscousLayersHyp )
+  if ((int) hyps.size() != (bool)_viscousLayersHyp + (bool)_blockRenumberHyp )
     aStatus = HYP_INCOMPATIBLE;
+  else
+  {
+    if ( _viscousLayersHyp )
+      if ( !error( _viscousLayersHyp->CheckHypothesis( aMesh, aShape, aStatus )))
+        aStatus = HYP_BAD_PARAMETER;
+
+    if ( _blockRenumberHyp && aStatus == HYP_OK )
+      error( _blockRenumberHyp->CheckHypothesis( aMesh, aShape ));
+  }
 
   return aStatus == HYP_OK;
 }
@@ -150,6 +164,7 @@ namespace
   //=============================================================================
 
   typedef boost::shared_ptr< FaceQuadStruct > FaceQuadStructPtr;
+  typedef std::vector<gp_XYZ>                 TXYZColumn;
 
   // symbolic names of box sides
   enum EBoxSides{ B_BOTTOM=0, B_RIGHT, B_TOP, B_LEFT, B_FRONT, B_BACK, B_NB_SIDES };
@@ -157,6 +172,8 @@ namespace
   // symbolic names of sides of quadrangle
   enum EQuadSides{ Q_BOTTOM=0, Q_RIGHT, Q_TOP, Q_LEFT, Q_NB_SIDES };
 
+  enum EAxes{ COO_X=1, COO_Y, COO_Z };
+
   //=============================================================================
   /*!
    * \brief Container of nodes of structured mesh on a qudrangular geom FACE
@@ -169,9 +186,12 @@ namespace
     // map of (node parameter on EDGE) to (column (vector) of nodes)
     TParam2ColumnMap _u2nodesMap;
 
-    // node column's taken form _u2nodesMap taking into account sub-shape orientation
+    // node column's taken from _u2nodesMap taking into account sub-shape orientation
     vector<TNodeColumn> _columns;
 
+    // columns of normalized parameters of nodes within the unitary cube
+    vector<TXYZColumn> _ijkColumns;
+
     // geometry of a cube side
     TopoDS_Face _sideF;
 
@@ -183,11 +203,15 @@ namespace
     {
       return SMESH_TNodeXYZ( GetNode( iCol, iRow ));
     }
+    gp_XYZ& GetIJK(int iCol, int iRow)
+    {
+      return _ijkColumns[iCol][iRow];
+    }
   };
 
   //================================================================================
   /*!
-   * \brief Convertor of a pair of integers to a sole index
+   * \brief Converter of a pair of integers to a sole index
    */
   struct _Indexer
   {
@@ -197,26 +221,6 @@ namespace
     int operator()(const int x, const int y) const { return y * _xSize + x; }
   };
 
-  //================================================================================
-  /*!
-   * \brief Appends a range of node columns from a map to another map
-   */
-  template< class TMapIterator >
-  void append( TParam2ColumnMap& toMap, TMapIterator from, TMapIterator to )
-  {
-    const SMDS_MeshNode* lastNode = toMap.rbegin()->second[0];
-    const SMDS_MeshNode* firstNode = from->second[0];
-    if ( lastNode == firstNode )
-      from++;
-    double u = toMap.rbegin()->first;
-    for (; from != to; ++from )
-    {
-      u += 1;
-      TParam2ColumnMap::iterator u2nn = toMap.insert( toMap.end(), make_pair ( u, TNodeColumn()));
-      u2nn->second.swap( from->second );
-    }
-  }
-
   //================================================================================
   /*!
    * \brief Finds FaceQuadStruct having a side equal to a given one and rearranges
@@ -229,7 +233,7 @@ namespace
     for ( int i = 1; i < 6; ++i )
     {
       if ( !quad[i] ) continue;
-      for ( unsigned iS = 0; iS < quad[i]->side.size(); ++iS )
+      for ( size_t iS = 0; iS < quad[i]->side.size(); ++iS )
       {
         const StdMeshers_FaceSidePtr side2 = quad[i]->side[iS];
         if (( side->FirstVertex().IsSame( side2->FirstVertex() ) ||
@@ -242,9 +246,9 @@ namespace
           if ( iS != Q_BOTTOM )
           {
             vector< FaceQuadStruct::Side > newSides;
-            for ( unsigned j = iS; j < quad[i]->side.size(); ++j )
+            for ( size_t j = iS; j < quad[i]->side.size(); ++j )
               newSides.push_back( quad[i]->side[j] );
-            for ( unsigned j = 0; j < iS; ++j )
+            for ( size_t j = 0; j < iS; ++j )
               newSides.push_back( quad[i]->side[j] );
             quad[i]->side.swap( newSides );
           }
@@ -255,6 +259,204 @@ namespace
     }
     return foundQuad;
   }
+
+  //================================================================================
+  /*!
+   * \brief Put quads to aCubeSide in the order of enum EBoxSides
+   */
+  //================================================================================
+
+  bool arrangeQuads( FaceQuadStructPtr quad[ 6 ], _FaceGrid aCubeSide[ 6 ], bool reverseBottom )
+  {
+    swap( aCubeSide[B_BOTTOM]._quad, quad[0] );
+    if ( reverseBottom )
+      swap( aCubeSide[B_BOTTOM]._quad->side[ Q_RIGHT],// direct the bottom normal inside cube
+            aCubeSide[B_BOTTOM]._quad->side[ Q_LEFT ] );
+
+    aCubeSide[B_FRONT]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_BOTTOM], quad );
+    aCubeSide[B_RIGHT]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_RIGHT ], quad );
+    aCubeSide[B_BACK ]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_TOP   ], quad );
+    aCubeSide[B_LEFT ]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_LEFT  ], quad );
+    if ( aCubeSide[B_FRONT ]._quad )
+      aCubeSide[B_TOP]._quad = getQuadWithBottom( aCubeSide[B_FRONT ]._quad->side[Q_TOP ], quad );
+
+    for ( int i = 1; i < 6; ++i )
+      if ( !aCubeSide[i]._quad )
+        return false;
+    return true;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Rearrange block sides according to StdMeshers_BlockRenumber hypothesis
+   */
+  //================================================================================
+
+  bool arrangeForRenumber( _FaceGrid      blockSide[ 6 ],
+                           TopoDS_Vertex& v000,
+                           TopoDS_Vertex& v001 )
+  {
+    std::swap( blockSide[B_BOTTOM]._quad->side[ Q_RIGHT],// restore after arrangeQuads()
+               blockSide[B_BOTTOM]._quad->side[ Q_LEFT ] );
+
+    // find v000
+    TopTools_MapOfShape cornerVertices;
+    cornerVertices.Add(  blockSide[B_BOTTOM]._quad->side[Q_BOTTOM].grid->LastVertex()  );
+    cornerVertices.Add(  blockSide[B_BOTTOM]._quad->side[Q_BOTTOM].grid->FirstVertex() );
+    cornerVertices.Add(  blockSide[B_BOTTOM]._quad->side[Q_TOP   ].grid->LastVertex()  );
+    cornerVertices.Add(  blockSide[B_BOTTOM]._quad->side[Q_TOP   ].grid->FirstVertex() );
+    cornerVertices.Add(  blockSide[B_TOP   ]._quad->side[Q_BOTTOM].grid->FirstVertex() );
+    cornerVertices.Add(  blockSide[B_TOP   ]._quad->side[Q_BOTTOM].grid->LastVertex()  );
+    cornerVertices.Add(  blockSide[B_TOP   ]._quad->side[Q_TOP   ].grid->FirstVertex() );
+    cornerVertices.Add(  blockSide[B_TOP   ]._quad->side[Q_TOP   ].grid->LastVertex()  );
+
+    if ( v000.IsNull() )
+    {
+      // block CS is not defined;
+      // renumber only if the block has an edge parallel to an axis of global CS
+
+      v000 = StdMeshers_RenumberHelper::GetVertex000( cornerVertices );
+    }
+
+    Bnd_B3d bbox;
+    for ( auto it = cornerVertices.cbegin(); it != cornerVertices.cend(); ++it )
+      bbox.Add( BRep_Tool::Pnt( TopoDS::Vertex( *it )));
+    double tol = 1e-5 * Sqrt( bbox.SquareExtent() );
+
+    // get block edges starting at v000
+
+    std::vector< StdMeshers_FaceSidePtr > edgesAtV000;
+    std::vector< gp_Vec >                 edgeDir;
+    std::vector< int >                    iParallel; // 0 - none, 1 - X, 2 - Y, 3 - Z
+    TopTools_MapOfShape                   lastVertices;
+    for ( int iQ = 0; iQ < 6; ++iQ )
+    {
+      FaceQuadStructPtr quad = blockSide[iQ]._quad;
+      for ( size_t iS = 0; iS < quad->side.size() &&  edgesAtV000.size() < 3; ++iS )
+      {
+        StdMeshers_FaceSidePtr edge = quad->side[iS];
+        TopoDS_Vertex v1 = edge->FirstVertex(), v2 = edge->LastVertex();
+        if (( v1.IsSame( v000 ) && !lastVertices.Contains( v2 )) ||
+            ( v2.IsSame( v000 ) && !lastVertices.Contains( v1 )))
+        {
+          bool reverse = v2.IsSame( v000 );
+          if ( reverse )
+            std::swap( v1, v2 );
+          lastVertices.Add( v2 );
+
+          edgesAtV000.push_back( edge );
+
+          gp_Pnt pf = BRep_Tool::Pnt( v1 );
+          gp_Pnt pl = BRep_Tool::Pnt( v2 );
+          gp_Vec vec( pf, pl );
+          edgeDir.push_back( vec );
+
+          iParallel.push_back( 0 );
+          if ( !v001.IsNull() )
+          {
+            if ( v001.IsSame( v2 ))
+              iParallel.back() = 3;
+          }
+          else
+          {
+            bool isStraight = true;
+            for ( int iE = 0; iE < edge->NbEdges() &&  isStraight; ++iE )
+              isStraight = SMESH_Algo::IsStraight( edge->Edge( iE ));
+
+            // is parallel to a GCS axis?
+            if ( isStraight )
+            {
+              int nbDiff = (( Abs( vec.X() ) > tol ) +
+                            ( Abs( vec.Y() ) > tol ) +
+                            ( Abs( vec.Z() ) > tol ) );
+              if ( nbDiff == 1 )
+                iParallel.back() = ( Abs( vec.X() ) > tol ) ? 1 : ( Abs( vec.Y() ) > tol ) ? 2 : 3;
+            }
+            else
+            {
+              edgeDir.back() = gp_Vec( pf, edge->Value3d( reverse ? 0.99 : 0.01 ));
+            }
+          }
+        }
+      }
+    }
+    if ( std::accumulate( iParallel.begin(), iParallel.end(), 0 ) == 0 )
+      return false;
+
+    // find edge OZ and edge OX
+    StdMeshers_FaceSidePtr edgeOZ, edgeOX;
+    auto iZIt = std::find( iParallel.begin(), iParallel.end(), 3 );
+    if ( iZIt != iParallel.end() )
+    {
+      int i = std::distance( iParallel.begin(), iZIt );
+      edgeOZ = edgesAtV000[ i ];
+      int iE1 = SMESH_MesherHelper::WrapIndex( i + 1, edgesAtV000.size() );
+      int iE2 = SMESH_MesherHelper::WrapIndex( i + 2, edgesAtV000.size() );
+      if (( edgeDir[ iE1 ] ^ edgeDir[ iE2 ] ) * edgeDir[ i ] < 0 )
+        std::swap( iE1, iE2 );
+      edgeOX = edgesAtV000[ iE1 ];
+    }
+    else
+    {
+      for ( size_t i = 0; i < edgesAtV000.size(); ++i )
+      {
+        if ( !iParallel[ i ] )
+          continue;
+        int iE1 = SMESH_MesherHelper::WrapIndex( i + 1, edgesAtV000.size() );
+        int iE2 = SMESH_MesherHelper::WrapIndex( i + 2, edgesAtV000.size() );
+        if (( edgeDir[ iE1 ] ^ edgeDir[ iE2 ] ) * edgeDir[ i ] < 0 )
+          std::swap( iE1, iE2 );
+        edgeOZ = edgesAtV000[ iParallel[i] == 1 ? iE2 : iE1 ];
+        edgeOX = edgesAtV000[ iParallel[i] == 1 ? i : iE1 ];
+        break;
+      }
+    }
+
+    if ( !edgeOZ || !edgeOX )
+      return false;
+
+    TopoDS_Vertex v100 = edgeOX->LastVertex();
+    if ( v100.IsSame( v000 ))
+      v100 = edgeOX->FirstVertex();
+
+    // Find the left quad, one including v000 but not v100
+
+    for ( int iQ = 0; iQ < 6; ++iQ )
+    {
+      FaceQuadStructPtr quad = blockSide[iQ]._quad;
+      bool hasV000 = false, hasV100 = false;
+      for ( size_t iS = 0; iS < quad->side.size(); ++iS )
+      {
+        StdMeshers_FaceSidePtr edge = quad->side[iS];
+        if ( edge->FirstVertex().IsSame( v000 ) || edge->LastVertex().IsSame( v000 ))
+          hasV000 = true;
+        if ( edge->FirstVertex().IsSame( v100 ) || edge->LastVertex().IsSame( v100 ))
+          hasV100 = true;
+      }
+      if ( hasV000 && !hasV100 )
+      {
+        // orient the left quad
+        for ( int i = 0; i < 4; ++i )
+        {
+          if ( quad->side[Q_BOTTOM].grid->Edge(0).IsSame( edgeOZ->Edge(0) ))
+            break;
+          quad->shift( 1, true );
+        }
+
+        FaceQuadStructPtr quads[ 6 ];
+        quads[0].swap( blockSide[iQ]._quad );
+        for ( int i = 1, j = 0; i < 6; ++i, ++j )
+          if ( blockSide[ j ]._quad )
+            quads[ i ].swap( blockSide[ j ]._quad );
+          else
+            --i;
+
+        return arrangeQuads( quads, blockSide, false/* true*/ );
+      }
+    }
+    return false;
+  }
+
   //================================================================================
   /*!
    * \brief Returns true if the 1st base node of sideGrid1 belongs to sideGrid2
@@ -282,6 +484,56 @@ namespace
     }
     return ( n == n00 || n == n01 || n == n10 || n == n11 );
   }
+
+  //================================================================================
+  /*!
+   * \brief Fill in _FaceGrid::_ijkColumns
+   *  \param [in,out] fg - a _FaceGrid
+   *  \param [in] i1 - coordinate index along _columns
+   *  \param [in] i2 - coordinate index along _columns[i]
+   *  \param [in] v3 - value of the constant parameter
+   */
+  //================================================================================
+
+  void computeIJK( _FaceGrid& fg, int i1, int i2, double v3 )
+  {
+    gp_XYZ ijk( v3, v3, v3 );
+    const size_t nbCol = fg._columns.size();
+    const size_t nbRow = fg._columns[0].size();
+
+    fg._ijkColumns.resize( nbCol );
+    for ( size_t i = 0; i < nbCol; ++i )
+      fg._ijkColumns[ i ].resize( nbRow, ijk );
+
+    vector< double > len( nbRow );
+    len[0] = 0;
+    for ( size_t i = 0; i < nbCol; ++i )
+    {
+      gp_Pnt pPrev = fg.GetXYZ( i, 0 );
+      for ( size_t j = 1; j < nbRow; ++j )
+      {
+        gp_Pnt p = fg.GetXYZ( i, j );
+        len[ j ] = len[ j-1 ] + p.Distance( pPrev );
+        pPrev = p;
+      }
+      for ( size_t j = 0; j < nbRow; ++j )
+        fg.GetIJK( i, j ).SetCoord( i2, len[ j ]/len.back() );
+    }
+
+    len.resize( nbCol );
+    for ( size_t j = 0; j < nbRow; ++j )
+    {
+      gp_Pnt pPrev = fg.GetXYZ( 0, j );
+      for ( size_t i = 1; i < nbCol; ++i )
+      {
+        gp_Pnt p = fg.GetXYZ( i, j );
+        len[ i ] = len[ i-1 ] + p.Distance( pPrev );
+        pPrev = p;
+      }
+      for ( size_t i = 0; i < nbCol; ++i )
+        fg.GetIJK( i, j ).SetCoord( i1, len[ i ]/len.back() );
+    }
+  }
 }
 
 //=============================================================================
@@ -299,7 +551,6 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh &         aMesh,
 {
   // PAL14921. Enable catching std::bad_alloc and Standard_OutOfMemory outside
   //Unexpect aCatch(SalomeException);
-  MESSAGE("StdMeshers_Hexa_3D::Compute");
   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
 
   // Shape verification
@@ -312,45 +563,46 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh &         aMesh,
   if ( exp.Next(), exp.More() )
     return error(COMPERR_BAD_SHAPE, "More than one SHELL in the geometry");
 
-  TopTools_IndexedMapOfShape FF;
+  TopTools_IndexedMapOfShape FF, EE;
   TopExp::MapShapes( aShape, TopAbs_FACE, FF);
   if ( FF.Extent() != 6)
   {
-    static StdMeshers_CompositeHexa_3D compositeHexa(_gen->GetANewId(), 0, _gen);
+    static StdMeshers_CompositeHexa_3D compositeHexa(_gen->GetANewId(), _gen);
+    compositeHexa.SetHypothesis( _blockRenumberHyp );
     if ( !compositeHexa.Compute( aMesh, aShape ))
       return error( compositeHexa.GetComputeError() );
-    return true;
+
+    return _blockRenumberHyp ? error( _blockRenumberHyp->CheckHypothesis( aMesh, aShape )) : true;
   }
 
   // Find sides of a cube
   // ---------------------
-  
+
+  // tool creating quadratic elements if needed
+  SMESH_MesherHelper helper (aMesh);
+  _quadraticMesh = helper.IsQuadraticSubMesh(aShape);
+
+  TopExp::MapShapes( aShape, TopAbs_EDGE, EE );
+  SMESH_MesherHelper* faceHelper = ( EE.Size() == 12 ) ? 0 : &helper;
+
   FaceQuadStructPtr quad[ 6 ];
-  StdMeshers_Quadrangle_2D quadAlgo( _gen->GetANewId(), GetStudyId(), _gen);
   for ( int i = 0; i < 6; ++i )
   {
-    if ( !( quad[i] = FaceQuadStructPtr( quadAlgo.CheckNbEdges( aMesh, FF( i+1 )))))
-      return error( quadAlgo.GetComputeError() );
+    if ( faceHelper )
+      faceHelper->SetSubShape( FF( i+1 ));
+    if ( !( quad[i] = FaceQuadStructPtr( _quadAlgo->CheckNbEdges( aMesh, FF( i+1 ),
+                                                                  /*considerMesh=*/true,
+                                                                  faceHelper))))
+      return error( _quadAlgo->GetComputeError() );
     if ( quad[i]->side.size() != 4 )
       return error( COMPERR_BAD_SHAPE, "Not a quadrangular box side" );
   }
 
+  // put quads in a proper order
   _FaceGrid aCubeSide[ 6 ];
+  if ( !arrangeQuads( quad, aCubeSide, true ))
+    return error( COMPERR_BAD_SHAPE );
 
-  swap( aCubeSide[B_BOTTOM]._quad, quad[0] );
-  swap( aCubeSide[B_BOTTOM]._quad->side[ Q_RIGHT],// direct the normal of bottom quad inside cube
-        aCubeSide[B_BOTTOM]._quad->side[ Q_LEFT ] );
-
-  aCubeSide[B_FRONT]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_BOTTOM], quad );
-  aCubeSide[B_RIGHT]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_RIGHT ], quad );
-  aCubeSide[B_BACK ]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_TOP   ], quad );
-  aCubeSide[B_LEFT ]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_LEFT  ], quad );
-  if ( aCubeSide[B_FRONT ]._quad )
-    aCubeSide[B_TOP]._quad = getQuadWithBottom( aCubeSide[B_FRONT ]._quad->side[Q_TOP ], quad );
-
-  for ( int i = 1; i < 6; ++i )
-    if ( !aCubeSide[i]._quad )
-      return error( COMPERR_BAD_SHAPE );
 
   // Make viscous layers
   // --------------------
@@ -371,8 +623,9 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh &         aMesh,
     for ( int i = 0; i < 6; ++i )
     {
       const TopoDS_Face& sideF = aCubeSide[i]._quad->face;
-      if ( !SMESH_MesherHelper::IsSameElemGeometry( meshDS->MeshElements( sideF ),
-                                                    SMDSGeom_QUADRANGLE,
+      const SMESHDS_SubMesh* smDS =
+        proxymesh ? proxymesh->GetSubMesh( sideF ) : meshDS->MeshElements( sideF );
+      if ( !SMESH_MesherHelper::IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE,
                                                     /*nullSubMeshRes=*/false ))
       {
         SMESH_ComputeErrorPtr err = ComputePentahedralMesh(aMesh, aShape, proxymesh.get());
@@ -381,13 +634,25 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh &         aMesh,
     }
   }
 
+  // Arrange sides according to _blockRenumberHyp
+  bool toRenumber = _blockRenumberHyp;
+  if ( toRenumber )
+  {
+    TopoDS_Vertex v000, v001;
+    _blockRenumberHyp->IsSolidIncluded( aMesh, aShape, v000, v001 );
+
+    toRenumber = arrangeForRenumber( aCubeSide, v000, v001 );
+
+    if ( toRenumber )
+    {
+      meshDS->Modified();
+      meshDS->CompactMesh(); // remove numbering holes
+    }
+  }
+
   // Check presence of regular grid mesh on FACEs of the cube
   // ------------------------------------------------------------
 
-  // tool creating quadratic elements if needed
-  SMESH_MesherHelper helper (aMesh);
-  _quadraticMesh = helper.IsQuadraticSubMesh(aShape);
-
   for ( int i = 0; i < 6; ++i )
   {
     const TopoDS_Face& F = aCubeSide[i]._quad->face;
@@ -449,19 +714,19 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh &         aMesh,
   {
     aCubeSide[i]._columns.resize( aCubeSide[i]._u2nodesMap.size() );
 
-    int iFwd = 0, iRev = aCubeSide[i]._columns.size()-1;
-    int* pi = isReverse[i] ? &iRev : &iFwd;
+    size_t iFwd = 0, iRev = aCubeSide[i]._columns.size()-1;
+    size_t*  pi = isReverse[i] ? &iRev : &iFwd;
     TParam2ColumnMap::iterator u2nn = aCubeSide[i]._u2nodesMap.begin();
     for ( ; iFwd < aCubeSide[i]._columns.size(); --iRev, ++iFwd, ++u2nn )
       aCubeSide[i]._columns[ *pi ].swap( u2nn->second );
 
     aCubeSide[i]._u2nodesMap.clear();
   }
-  
+
   if ( proxymesh )
     for ( int i = 0; i < 6; ++i )
-      for ( unsigned j = 0; j < aCubeSide[i]._columns.size(); ++j)
-        for ( unsigned k = 0; k < aCubeSide[i]._columns[j].size(); ++k)
+      for ( size_t j = 0; j < aCubeSide[i]._columns.size(); ++j)
+        for ( size_t k = 0; k < aCubeSide[i]._columns[j].size(); ++k)
         {
           const SMDS_MeshNode* & n = aCubeSide[i]._columns[j][k];
           n = proxymesh->GetProxyNode( n );
@@ -482,9 +747,23 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh &         aMesh,
   _FaceGrid* fBack   = & aCubeSide[ B_BACK   ];
 
   // cube size measured in nb of nodes
-  int x, xSize = fBottom->_columns.size() , X = xSize - 1;
-  int y, ySize = fLeft->_columns.size()   , Y = ySize - 1;
-  int z, zSize = fLeft->_columns[0].size(), Z = zSize - 1;
+  size_t x, xSize = fBottom->_columns.size() , X = xSize - 1;
+  size_t y, ySize = fLeft->_columns.size()   , Y = ySize - 1;
+  size_t z, zSize = fLeft->_columns[0].size(), Z = zSize - 1;
+
+  // check sharing of FACEs (IPAL54417)
+  if ( fFront ->_columns.size()    != xSize ||
+       fBack  ->_columns.size()    != xSize ||
+       fTop   ->_columns.size()    != xSize ||
+
+       fRight ->_columns.size()    != ySize ||
+       fTop   ->_columns[0].size() != ySize ||
+       fBottom->_columns[0].size() != ySize ||
+
+       fRight ->_columns[0].size() != zSize ||
+       fFront ->_columns[0].size() != zSize ||
+       fBack  ->_columns[0].size() != zSize )
+    return error( COMPERR_BAD_SHAPE, "Not sewed faces" );
 
   // columns of internal nodes "rising" from nodes of fBottom
   _Indexer colIndex( xSize, ySize );
@@ -522,6 +801,16 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh &         aMesh,
     }
   }
 
+  // compute normalized parameters of nodes on sides (PAL23189)
+  computeIJK( *fBottom, COO_X, COO_Y, /*z=*/0. );
+  computeIJK( *fRight,  COO_Y, COO_Z, /*x=*/1. );
+  computeIJK( *fTop,    COO_X, COO_Y, /*z=*/1. );
+  computeIJK( *fLeft,   COO_Y, COO_Z, /*x=*/0. );
+  computeIJK( *fFront,  COO_X, COO_Z, /*y=*/0. );
+  computeIJK( *fBack,   COO_X, COO_Z, /*y=*/1. );
+
+  StdMeshers_RenumberHelper renumHelper( aMesh, _blockRenumberHyp );
+
   // projection points of the internal node on cube sub-shapes by which
   // coordinates of the internal node are computed
   vector<gp_XYZ> pointsOnShapes( SMESH_Block::ID_Shell );
@@ -536,13 +825,30 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh &         aMesh,
   pointsOnShapes[ SMESH_Block::ID_V011 ] = fTop->GetXYZ( 0, Y );
   pointsOnShapes[ SMESH_Block::ID_V111 ] = fTop->GetXYZ( X, Y );
 
+  gp_XYZ params; // normalized parameters of an internal node within the unit box
+
+  if ( toRenumber )
+    for ( y = 0; y < ySize; ++y )
+    {
+      vector< const SMDS_MeshNode* >& column0y = columns[ colIndex( 0, y )];
+      for ( z = 0; z < zSize; ++z )
+        renumHelper.AddReplacingNode( column0y[ z ] );
+    }
+
   for ( x = 1; x < xSize-1; ++x )
   {
-    gp_XYZ params; // normalized parameters of internal node within a unit box
-    params.SetCoord( 1, x / double(X) );
+    if ( toRenumber )
+    {
+      vector< const SMDS_MeshNode* >& columnX0 = columns[ colIndex( x, 0 )];
+      for ( z = 0; z < zSize; ++z )
+        renumHelper.AddReplacingNode( columnX0[ z ] );
+    }
+
+    const double rX = x / double(X);
     for ( y = 1; y < ySize-1; ++y )
     {
-      params.SetCoord( 2, y / double(Y) );
+      const double rY = y / double(Y);
+
       // a column to fill in during z loop
       vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )];
       // projection points on horizontal edges
@@ -557,18 +863,36 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh &         aMesh,
       // projection points on horizontal faces
       pointsOnShapes[ SMESH_Block::ID_Fxy0 ] = fBottom->GetXYZ( x, y );
       pointsOnShapes[ SMESH_Block::ID_Fxy1 ] = fTop   ->GetXYZ( x, y );
+
+      if ( toRenumber )
+        renumHelper.AddReplacingNode( column[ 0 ] );
+
       for ( z = 1; z < zSize-1; ++z ) // z loop
       {
-        params.SetCoord( 3, z / double(Z) );
+        const double rZ = z / double(Z);
+
+        const gp_XYZ& pBo = fBottom->GetIJK( x, y );
+        const gp_XYZ& pTo = fTop   ->GetIJK( x, y );
+        const gp_XYZ& pFr = fFront ->GetIJK( x, z );
+        const gp_XYZ& pBa = fBack  ->GetIJK( x, z );
+        const gp_XYZ& pLe = fLeft  ->GetIJK( y, z );
+        const gp_XYZ& pRi = fRight ->GetIJK( y, z );
+        params.SetCoord( 1, 0.5 * ( pBo.X() * ( 1. - rZ ) + pTo.X() * rZ  +
+                                    pFr.X() * ( 1. - rY ) + pBa.X() * rY ));
+        params.SetCoord( 2, 0.5 * ( pBo.Y() * ( 1. - rZ ) + pTo.Y() * rZ  +
+                                    pLe.Y() * ( 1. - rX ) + pRi.Y() * rX ));
+        params.SetCoord( 3, 0.5 * ( pFr.Z() * ( 1. - rY ) + pBa.Z() * rY  +
+                                    pLe.Z() * ( 1. - rX ) + pRi.Z() * rX ));
+
         // projection points on vertical edges
-        pointsOnShapes[ SMESH_Block::ID_E00z ] = fFront->GetXYZ( 0, z );    
-        pointsOnShapes[ SMESH_Block::ID_E10z ] = fFront->GetXYZ( X, z );    
-        pointsOnShapes[ SMESH_Block::ID_E01z ] = fBack->GetXYZ( 0, z );    
+        pointsOnShapes[ SMESH_Block::ID_E00z ] = fFront->GetXYZ( 0, z );
+        pointsOnShapes[ SMESH_Block::ID_E10z ] = fFront->GetXYZ( X, z );
+        pointsOnShapes[ SMESH_Block::ID_E01z ] = fBack->GetXYZ( 0, z );
         pointsOnShapes[ SMESH_Block::ID_E11z ] = fBack->GetXYZ( X, z );
         // projection points on vertical faces
-        pointsOnShapes[ SMESH_Block::ID_Fx0z ] = fFront->GetXYZ( x, z );    
-        pointsOnShapes[ SMESH_Block::ID_Fx1z ] = fBack ->GetXYZ( x, z );    
-        pointsOnShapes[ SMESH_Block::ID_F0yz ] = fLeft ->GetXYZ( y, z );    
+        pointsOnShapes[ SMESH_Block::ID_Fx0z ] = fFront->GetXYZ( x, z );
+        pointsOnShapes[ SMESH_Block::ID_Fx1z ] = fBack ->GetXYZ( x, z );
+        pointsOnShapes[ SMESH_Block::ID_F0yz ] = fLeft ->GetXYZ( y, z );
         pointsOnShapes[ SMESH_Block::ID_F1yz ] = fRight->GetXYZ( y, z );
 
         // compute internal node coordinates
@@ -576,13 +900,30 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh &         aMesh,
         SMESH_Block::ShellPoint( params, pointsOnShapes, coords );
         column[ z ] = helper.AddNode( coords.X(), coords.Y(), coords.Z() );
 
-      }
+      } // z loop
+      if ( toRenumber )
+        renumHelper.AddReplacingNode( column[ Z ] );
+
+    } // y loop
+    if ( toRenumber )
+    {
+      vector< const SMDS_MeshNode* >& columnX0 = columns[ colIndex( x, Y )];
+      for ( z = 0; z < zSize; ++z )
+        renumHelper.AddReplacingNode( columnX0[ z ] );
+    }
+  } // x loop
+
+  if ( toRenumber )
+    for ( y = 0; y < ySize; ++y )
+    {
+      vector< const SMDS_MeshNode* >& columnXy = columns[ colIndex( X, y )];
+      for ( z = 0; z < zSize; ++z )
+        renumHelper.AddReplacingNode( columnXy[ z ] );
     }
-  }
 
   // side data no more needed, free memory
   for ( int i = 0; i < 6; ++i )
-    aCubeSide[i]._columns.clear();
+    SMESHUtils::FreeVector( aCubeSide[i]._columns );
 
   // 5) Create hexahedrons
   // ---------------------
@@ -596,11 +937,25 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh &         aMesh,
       for ( z = 0; z < zSize-1; ++z )
       {
         // bottom face normal of a hexa mush point outside the volume
-        helper.AddVolume(col00[z],   col01[z],   col11[z],   col10[z],
-                         col00[z+1], col01[z+1], col11[z+1], col10[z+1]);
+        if ( toRenumber )
+          helper.AddVolume(col00[z], col01[z], col01[z+1], col00[z+1],
+                           col10[z], col11[z], col11[z+1], col10[z+1]);
+        else
+          helper.AddVolume(col00[z],   col01[z],   col11[z],   col10[z],
+                           col00[z+1], col01[z+1], col11[z+1], col10[z+1]);
       }
     }
   }
+
+  if ( toRenumber )
+    renumHelper.DoReplaceNodes();
+
+
+  if ( _blockRenumberHyp )
+  {
+    return error( _blockRenumberHyp->CheckHypothesis( aMesh, aShape ));
+  }
+
   return true;
 }
 
@@ -624,7 +979,7 @@ bool StdMeshers_Hexa_3D::Evaluate(SMESH_Mesh & aMesh,
   }
   if (meshFaces.size() != 6) {
     //return error(COMPERR_BAD_SHAPE, TComm(meshFaces.size())<<" instead of 6 faces in a block");
-    static StdMeshers_CompositeHexa_3D compositeHexa(-10, 0, aMesh.GetGen());
+    static StdMeshers_CompositeHexa_3D compositeHexa(-10, aMesh.GetGen());
     return compositeHexa.Evaluate(aMesh, aShape, aResMap);
   }
   
@@ -734,7 +1089,7 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh & aMesh, SMESH_MesherHelper* aHelper
   static StdMeshers_HexaFromSkin_3D * algo = 0;
   if ( !algo ) {
     SMESH_Gen* gen = aMesh.GetGen();
-    algo = new StdMeshers_HexaFromSkin_3D( gen->GetANewId(), 0, gen );
+    algo = new StdMeshers_HexaFromSkin_3D( gen->GetANewId(), gen );
   }
   algo->InitComputeError();
   algo->Compute( aMesh, aHelper );
@@ -746,34 +1101,30 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh & aMesh, SMESH_MesherHelper* aHelper
  * \brief Return true if the algorithm can mesh this shape
  *  \param [in] aShape - shape to check
  *  \param [in] toCheckAll - if true, this check returns OK if all shapes are OK,
- *              else, returns OK if all at least one shape is OK
+ *              else, returns OK if at least one shape is OK
  */
 //================================================================================
 
 bool StdMeshers_Hexa_3D::IsApplicable( const TopoDS_Shape & aShape, bool toCheckAll )
 {
-  TopoDS_Vertex theVertex0, theVertex1;
-  TopTools_IndexedMapOfOrientedShape theShapeIDMap;
-  bool isCurShellApp;
-  int nbFoundShells = 0;
   TopExp_Explorer exp0( aShape, TopAbs_SOLID );
   if ( !exp0.More() ) return false;
+
   for ( ; exp0.More(); exp0.Next() )
   {
-    nbFoundShells = 0;
-    isCurShellApp = false;
+    int nbFoundShells = 0;
     TopExp_Explorer exp1( exp0.Current(), TopAbs_SHELL );
     for ( ; exp1.More(); exp1.Next(), ++nbFoundShells)
       if ( nbFoundShells == 2 ) break;
-    if ( nbFoundShells == 2){
+    if ( nbFoundShells != 1 ) {
       if ( toCheckAll ) return false;
       continue;
     }   
-    exp1.Init( exp0.Current(), TopAbs_SHELL );
-    const TopoDS_Shell& shell = TopoDS::Shell(exp1.Current());
-    isCurShellApp = SMESH_Block::FindBlockShapes(shell, theVertex0, theVertex1, theShapeIDMap );
-    if ( toCheckAll && !isCurShellApp ) return false;
-    if ( !toCheckAll && isCurShellApp ) return true;
+    exp1.Init( exp0.Current(), TopAbs_FACE );
+    int nbEdges = SMESH_MesherHelper::Count( exp1.Current(), TopAbs_EDGE, /*ignoreSame=*/true );
+    bool ok = ( nbEdges > 3 );
+    if ( toCheckAll && !ok ) return false;
+    if ( !toCheckAll && ok ) return true;
   }
   return toCheckAll;
 };
@@ -806,7 +1157,7 @@ SMESH_ComputeErrorPtr ComputePentahedralMesh(SMESH_Mesh &          aMesh,
     static StdMeshers_Prism_3D * aPrism3D = 0;
     if ( !aPrism3D ) {
       SMESH_Gen* gen = aMesh.GetGen();
-      aPrism3D = new StdMeshers_Prism_3D( gen->GetANewId(), 0, gen );
+      aPrism3D = new StdMeshers_Prism_3D( gen->GetANewId(), gen );
     }
     SMESH_Hypothesis::Hypothesis_Status aStatus;
     if ( aPrism3D->CheckHypothesis( aMesh, aShape, aStatus ) ) {
@@ -837,7 +1188,7 @@ bool EvaluatePentahedralMesh(SMESH_Mesh & aMesh,
     static StdMeshers_Prism_3D * aPrism3D = 0;
     if ( !aPrism3D ) {
       SMESH_Gen* gen = aMesh.GetGen();
-      aPrism3D = new StdMeshers_Prism_3D( gen->GetANewId(), 0, gen );
+      aPrism3D = new StdMeshers_Prism_3D( gen->GetANewId(), gen );
     }
     SMESH_Hypothesis::Hypothesis_Status aStatus;
     if ( aPrism3D->CheckHypothesis( aMesh, aShape, aStatus ) ) {