Salome HOME
bos #20256: [CEA 18523] Porting SMESH to int 64 bits
[modules/smesh.git] / src / StdMeshers / StdMeshers_Prism_3D.cxx
index cb11b0613940b3ef7fd006a4037732779cdfda01..962ae75bd23dda4bba31fe485dd5f13932ec2c8f 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2021  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
@@ -89,20 +89,48 @@ enum { ID_BOT_FACE = SMESH_Block::ID_Fxy0,
        BOTTOM_EDGE = 0, TOP_EDGE, V0_EDGE, V1_EDGE, // edge IDs in face
        NB_WALL_FACES = 4 }; //
 
-namespace {
-
+namespace
+{
+  //=======================================================================
+  /*!
+   * \brief Auxiliary mesh
+   */
+  struct TmpMesh: public SMESH_Mesh
+  {
+    TmpMesh() {
+      _isShapeToMesh = (_id = 0);
+      _myMeshDS  = new SMESHDS_Mesh( _id, true );
+    }
+  };
   //=======================================================================
   /*!
    * \brief Quadrangle algorithm
    */
-  struct TQuadrangleAlgo : public StdMeshers_Quadrangle_2D
+  class TQuadrangleAlgo : public StdMeshers_Quadrangle_2D
   {
+    typedef NCollection_DataMap< TopoDS_Face, FaceQuadStruct::Ptr > TFace2QuadMap;
+    TFace2QuadMap myFace2QuadMap;
+
     TQuadrangleAlgo(SMESH_Gen* gen)
       : StdMeshers_Quadrangle_2D( gen->GetANewId(), gen)
     {
     }
-    static StdMeshers_Quadrangle_2D* instance( SMESH_Algo*         fatherAlgo,
-                                               SMESH_MesherHelper* helper=0)
+  public:
+
+    //================================================================================
+    // Clear data of TQuadrangleAlgo at destruction
+    struct Cleaner
+    {
+      TQuadrangleAlgo* myAlgo;
+
+      Cleaner(TQuadrangleAlgo* algo): myAlgo( algo ){}
+      ~Cleaner() { myAlgo->reset(); }
+    };
+
+    //================================================================================
+    // Return TQuadrangleAlgo singleton
+    static TQuadrangleAlgo* instance( SMESH_Algo*         fatherAlgo,
+                                      SMESH_MesherHelper* helper=0)
     {
       static TQuadrangleAlgo* algo = new TQuadrangleAlgo( fatherAlgo->GetGen() );
       if ( helper &&
@@ -118,7 +146,124 @@ namespace {
 
       return algo;
     }
+
+    //================================================================================
+    // Clear collected data
+    void reset()
+    {
+      StdMeshers_Quadrangle_2D::myQuadList.clear();
+      StdMeshers_Quadrangle_2D::myHelper = nullptr;
+      StdMeshers_Quadrangle_2D::myProxyMesh.reset();
+      myFace2QuadMap.Clear();
+    }
+
+    //================================================================================
+    /*!
+     * \brief Return FaceQuadStruct if a given FACE can be meshed by StdMeshers_Quadrangle_2D
+     */
+    FaceQuadStruct::Ptr CheckNbEdges(SMESH_Mesh&         theMesh,
+                                     const TopoDS_Shape& theShape )
+    {
+      const TopoDS_Face& face = TopoDS::Face( theShape );
+      if ( myFace2QuadMap.IsBound( face ))
+        return myFace2QuadMap.Find( face );
+
+      FaceQuadStruct::Ptr &  resultQuad = * myFace2QuadMap.Bound( face, FaceQuadStruct::Ptr() );
+
+      FaceQuadStruct::Ptr quad =
+        StdMeshers_Quadrangle_2D::CheckNbEdges( theMesh, face, /*considerMesh=*/false, myHelper );
+      if ( quad )
+      {
+        // check if the quadrangle mesh would be valid
+
+        // check existing 1D mesh
+        // int nbSegments[4], i = 0;
+        // for ( FaceQuadStruct::Side & side : quad->side )
+        //   nbSegments[ i++ ] = side.grid->NbSegments();
+        // if ( nbSegments[0] > 0 && nbSegments[2] > 0 && nbSegments[0] != nbSegments[2] ||
+        //      nbSegments[1] > 0 && nbSegments[3] > 0 && nbSegments[1] != nbSegments[3] )
+        //   return resultQuad;
+
+        int nbEdges = 0;
+        for ( FaceQuadStruct::Side & side : quad->side )
+          nbEdges += side.grid->NbEdges();
+        if ( nbEdges == 4 )
+          return resultQuad = quad;
+
+        TmpMesh mesh;
+        mesh.ShapeToMesh( face );
+        SMESHDS_Mesh* meshDS = mesh.GetMeshDS();
+        SMESH_MesherHelper helper( mesh );
+        helper.SetSubShape( face );
+        helper.SetElementsOnShape( true );
+
+        // create nodes on all VERTEX'es
+        for ( TopExp_Explorer vert( face, TopAbs_VERTEX ); vert.More(); vert.Next() )
+          mesh.GetSubMesh( vert.Current() )->ComputeStateEngine( SMESH_subMesh::COMPUTE );
+
+        FaceQuadStruct::Ptr tmpQuad( new FaceQuadStruct() );
+        tmpQuad->side.resize( 4 );
+
+        // divide quad sides into halves at least
+        const SMDS_MeshNode* node;
+        for ( int iDir = 0; iDir < 2; ++iDir )
+        {
+          StdMeshers_FaceSidePtr sides[2] = { quad->side[iDir], quad->side[iDir+2] };
+          std::map< double, const SMDS_MeshNode* > nodes[2];
+          for ( int iS : { 0, 1 } )
+          {
+            node = SMESH_Algo::VertexNode( sides[iS]->FirstVertex(), meshDS );
+            nodes[iS].insert( std::make_pair( 0, node ));
+            double curLen = 0;
+            for ( int iE = 1; iE < sides[iS]->NbEdges(); ++iE )
+            {
+              curLen += sides[iS]->EdgeLength( iE - 1 );
+              double u = curLen / sides[iS]->Length();
+              node = SMESH_Algo::VertexNode( sides[iS]->FirstVertex( iE ), meshDS );
+              nodes[iS  ].insert( std::make_pair( u, node ));
+              nodes[1-iS].insert( std::make_pair( u, nullptr ));
+            }
+            nodes[iS].insert( std::make_pair( 0.5, nullptr ));
+            node = SMESH_Algo::VertexNode( sides[iS]->LastVertex(), meshDS );
+            nodes[iS].insert( std::make_pair( 1, node ));
+          }
+
+          for ( int iS : { 0, 1 } )
+          {
+            UVPtStructVec sideNodes;
+            sideNodes.reserve( nodes[ iS ].size() );
+            for ( auto & u_node : nodes[ iS ])
+            {
+              if ( !u_node.second )
+              {
+                gp_Pnt p = sides[iS]->Value3d( u_node.first );
+                u_node.second = meshDS->AddNode( p.X(), p.Y(), p.Z() );
+                TopoDS_Edge edge;
+                double param = sides[iS]->Parameter( u_node.first, edge );
+                meshDS->SetNodeOnEdge( u_node.second, edge, param );
+              }
+              sideNodes.push_back( u_node.second );
+              sideNodes.back().SetUV( helper.GetNodeUV( face, u_node.second ));
+            }
+            tmpQuad->side[ iS ? iDir+2 : iDir ] = StdMeshers_FaceSide::New( sideNodes, face );
+          }
+        }
+        StdMeshers_Quadrangle_2D::myCheckOri = true;
+        StdMeshers_Quadrangle_2D::myQuadList.clear();
+        StdMeshers_Quadrangle_2D::myQuadList.push_back( tmpQuad );
+        StdMeshers_Quadrangle_2D::myHelper = &helper;
+        if ( StdMeshers_Quadrangle_2D::computeQuadDominant( mesh, face, tmpQuad ) &&
+             StdMeshers_Quadrangle_2D::check())
+        {
+          resultQuad = quad;
+        }
+        StdMeshers_Quadrangle_2D::myQuadList.clear();
+        StdMeshers_Quadrangle_2D::myHelper = nullptr;
+      }
+      return resultQuad;
+    }
   };
+
   //=======================================================================
   /*!
    * \brief Algorithm projecting 1D mesh
@@ -400,7 +545,7 @@ namespace {
 
   int removeQuasiQuads(list< SMESH_subMesh* >&   notQuadSubMesh,
                        SMESH_MesherHelper*       helper,
-                       StdMeshers_Quadrangle_2D* quadAlgo)
+                       TQuadrangleAlgo*          quadAlgo)
   {
     int nbRemoved = 0;
     //SMESHDS_Mesh* mesh = notQuadSubMesh.front()->GetFather()->GetMeshDS();
@@ -409,7 +554,7 @@ namespace {
     {
       SMESH_subMesh* faceSm = *smIt;
       SMESHDS_SubMesh* faceSmDS = faceSm->GetSubMeshDS();
-      int nbQuads = faceSmDS ? faceSmDS->NbElements() : 0;
+      smIdType nbQuads = faceSmDS ? faceSmDS->NbElements() : 0;
       bool toRemove;
       if ( nbQuads > 0 )
         toRemove = helper->IsStructured( faceSm );
@@ -450,7 +595,7 @@ namespace {
   //================================================================================
 
   int countNbSides( const Prism_3D::TPrismTopo & thePrism,
-                    vector<int> &                nbUnitePerEdge,
+                    vector<int> &                /*nbUnitePerEdge*/,
                     vector< double > &           edgeLength)
   {
     int nbEdges = thePrism.myNbEdgesInWires.front();  // nb outer edges
@@ -528,6 +673,22 @@ namespace {
     return nbSides;
   }
 
+  //================================================================================
+  /*!
+   * \brief Count EDGEs ignoring degenerated ones
+   */
+  //================================================================================
+
+  int CountEdges( const TopoDS_Face& face )
+  {
+    int nbE = 0;
+    for ( TopExp_Explorer edgeExp( face, TopAbs_EDGE ); edgeExp.More(); edgeExp.Next() )
+      if ( !SMESH_Algo::isDegenerated( TopoDS::Edge( edgeExp.Current() )))
+        ++nbE;
+
+    return nbE;
+  }
+
   //================================================================================
   /*!
    * \brief Set/get wire index to FaceQuadStruct
@@ -557,8 +718,11 @@ namespace {
       cout << "mesh.AddNode( " << p[i].X() << ", "<< p[i].Y() << ", "<< p[i].Z() << ") # " << i <<" " ;
       SMESH_Block::DumpShapeID( i, cout ) << endl;
     }
+#else
+    (void)p; // unused in release mode
 #endif
   }
+
 } // namespace
 
 //=======================================================================
@@ -598,8 +762,8 @@ StdMeshers_Prism_3D::~StdMeshers_Prism_3D()
 //purpose  :
 //=======================================================================
 
-bool StdMeshers_Prism_3D::CheckHypothesis(SMESH_Mesh&                          aMesh,
-                                          const TopoDS_Shape&                  aShape,
+bool StdMeshers_Prism_3D::CheckHypothesis(SMESH_Mesh&                          /*aMesh*/,
+                                          const TopoDS_Shape&                  /*aShape*/,
                                           SMESH_Hypothesis::Hypothesis_Status& aStatus)
 {
   // no hypothesis
@@ -617,6 +781,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
   SMESH_MesherHelper helper( theMesh );
   myHelper = &helper;
   myPrevBottomSM = 0;
+  TQuadrangleAlgo::Cleaner quadCleaner( TQuadrangleAlgo::instance( this ));
 
   int nbSolids = helper.Count( theShape, TopAbs_SOLID, /*skipSame=*/false );
   if ( nbSolids < 1 )
@@ -628,7 +793,6 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
   // look for meshed FACEs ("source" FACEs) that must be prism bottoms
   list< TopoDS_Face > meshedFaces, notQuadMeshedFaces, notQuadFaces;
   const bool meshHasQuads = ( theMesh.NbQuadrangles() > 0 );
-  //StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this );
   for ( int iF = 1; iF <= faceToSolids.Extent(); ++iF )
   {
     const TopoDS_Face& face = TopoDS::Face( faceToSolids.FindKey( iF ));
@@ -687,6 +851,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
   }
 
   TopTools_MapOfShape meshedSolids;
+  NCollection_DataMap< TopoDS_Shape, SMESH_subMesh* > meshedFace2AlgoSM;
   list< Prism_3D::TPrismTopo > meshedPrism;
   list< TopoDS_Face > suspectSourceFaces;
   TopTools_ListIteratorOfListOfShape solidIt;
@@ -710,14 +875,22 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
         {
           prism.Clear();
           prism.myBottom = face;
+          if ( meshedFace2AlgoSM.IsBound( face ))
+            prism.myAlgoSM = meshedFace2AlgoSM.Find( face );
           if ( !initPrism( prism, solid, selectBottom ) ||
                !compute( prism ))
             return false;
 
           SMESHDS_SubMesh* smDS = theMesh.GetMeshDS()->MeshElements( prism.myTop );
-          if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE ))
+          if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE ) ||
+               !myHelper->IsStructured( theMesh.GetSubMesh( prism.myTop )))
           {
             meshedFaces.push_front( prism.myTop );
+            if ( prism.myAlgoSM  && prism.myAlgoSM->GetAlgo() )
+            {
+              meshedFace2AlgoSM.Bind( prism.myTop,    prism.myAlgoSM );
+              meshedFace2AlgoSM.Bind( prism.myBottom, prism.myAlgoSM );
+            }
           }
           else
           {
@@ -752,9 +925,18 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
               solidList.Remove( solidIt );
               continue; // already computed prism
             }
-            if ( myHelper->IsBlock( solid )) {
-              solidIt.Next();
-              continue; // too trivial
+            if ( myHelper->IsBlock( solid ))
+            {
+              bool isStructBase = true;
+              if ( prismIt->myAlgoSM )
+                isStructBase = ( myHelper->IsSameElemGeometry( prismIt->myAlgoSM->GetSubMeshDS(),
+                                                               SMDSGeom_QUADRANGLE ) &&
+                                 myHelper->IsStructured(prismIt->myAlgoSM ));
+              if ( isStructBase )
+              {
+                solidIt.Next();
+                continue; // too trivial
+              }
             }
             // find a source FACE of the SOLID: it's a FACE sharing a bottom EDGE with wFace
             const TopoDS_Edge& wEdge = (*wQuad)->side[ QUAD_TOP_SIDE ].grid->Edge(0);
@@ -773,27 +955,41 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
                 }
               prism.Clear();
               prism.myBottom = candidateF;
+              prism.myAlgoSM = prismIt->myAlgoSM;
               mySetErrorToSM = false;
               if ( !myHelper->IsSubShape( candidateF, prismIt->myShape3D ) &&
                    myHelper ->IsSubShape( candidateF, solid ) &&
                    !myHelper->GetMesh()->GetSubMesh( candidateF )->IsMeshComputed() &&
                    initPrism( prism, solid, /*selectBottom=*/false ) &&
                    !myHelper->GetMesh()->GetSubMesh( prism.myTop )->IsMeshComputed() &&
-                   !myHelper->GetMesh()->GetSubMesh( prism.myBottom )->IsMeshComputed() &&
-                   project2dMesh( sourceF, prism.myBottom ))
+                   !myHelper->GetMesh()->GetSubMesh( prism.myBottom )->IsMeshComputed() )
               {
-                mySetErrorToSM = true;
-                if ( !compute( prism ))
-                  return false;
-                SMESHDS_SubMesh* smDS = theMesh.GetMeshDS()->MeshElements( prism.myTop );
-                if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE ))
+                if ( project2dMesh( sourceF, prism.myBottom ))
+                {
+                  mySetErrorToSM = true;
+                  if ( !compute( prism ))
+                    return false;
+                  SMESHDS_SubMesh* smDS = theMesh.GetMeshDS()->MeshElements( prism.myTop );
+                  if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE ))
+                  {
+                    meshedFaces.push_front( prism.myTop );
+                    meshedFaces.push_front( prism.myBottom );
+                    selectBottom = false;
+                    if ( prism.myAlgoSM  && prism.myAlgoSM->GetAlgo() )
+                    {
+                      meshedFace2AlgoSM.Bind( prism.myTop, prism.myAlgoSM );
+                      meshedFace2AlgoSM.Bind( prism.myBottom, prism.myAlgoSM );
+                    }
+                  }
+                  meshedPrism.push_back( prism );
+                  meshedSolids.Add( solid );
+                }
+                else
                 {
-                  meshedFaces.push_front( prism.myTop );
-                  meshedFaces.push_front( prism.myBottom );
-                  selectBottom = false;
+                  suspectSourceFaces.push_back( prism.myBottom );
+                  if ( prism.myAlgoSM && prism.myAlgoSM->GetAlgo() )
+                    meshedFace2AlgoSM.Bind( prism.myBottom, prism.myAlgoSM );
                 }
-                meshedPrism.push_back( prism );
-                meshedSolids.Add( solid );
               }
               InitComputeError();
             }
@@ -829,7 +1025,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
         SMESH_subMesh*                 faceSM = theMesh.GetSubMesh( face );
         if ( !faceSM->IsEmpty() )
         {
-          int nbFaces = faceSM->GetSubMeshDS()->NbElements();
+          smIdType nbFaces = faceSM->GetSubMeshDS()->NbElements();
           if ( prevNbFaces < nbFaces )
           {
             if ( !meshedFaces.empty() ) meshedFaces.pop_back();
@@ -846,7 +1042,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
             allSubMeComputed = smIt->next()->IsMeshComputed();
           if ( allSubMeComputed )
           {
-            faceSM->ComputeStateEngine( SMESH_subMesh::COMPUTE );
+            faceSM->ComputeStateEngine( SMESH_subMesh::COMPUTE_SUBMESH );
             if ( !faceSM->IsEmpty() ) {
               meshedFaces.push_front( face ); // higher priority
               selectBottom = true;
@@ -919,7 +1115,7 @@ bool StdMeshers_Prism_3D::getWallFaces( Prism_3D::TPrismTopo & thePrism,
 
   SMESH_Mesh* mesh = myHelper->GetMesh();
 
-  StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this, myHelper );
+  TQuadrangleAlgo* quadAlgo = TQuadrangleAlgo::instance( this, myHelper );
 
   TopTools_MapOfShape faceMap;
   TopTools_IndexedDataMapOfShapeListOfShape edgeToFaces;
@@ -957,7 +1153,7 @@ bool StdMeshers_Prism_3D::getWallFaces( Prism_3D::TPrismTopo & thePrism,
           if ( !quadList.back() )
             return toSM( error(TCom("Side face #") << shapeID( face )
                                << " not meshable with quadrangles"));
-          bool isCompositeBase = ! setBottomEdge( *edge, quadList.back(), face );
+          bool isCompositeBase = ! setBottomEdge( *edge, quadList.back(), face ); // -> orient CCW
           if ( isCompositeBase )
           {
             // it's OK if all EDGEs of the bottom side belongs to the bottom FACE
@@ -1400,8 +1596,9 @@ bool StdMeshers_Prism_3D::computeBase(const Prism_3D::TPrismTopo& thePrism)
   {
     // find any applicable algorithm assigned to any FACE of the main shape
     std::vector< TopoDS_Shape > faces;
-    if ( myPrevBottomSM &&
-         myPrevBottomSM->GetAlgo()->IsApplicableToShape( thePrism.myBottom, /*all=*/false ))
+    if ( thePrism.myAlgoSM && thePrism.myAlgoSM->GetAlgo() )
+      faces.push_back( thePrism.myAlgoSM->GetSubShape() );
+    if ( myPrevBottomSM && myPrevBottomSM->GetAlgo() )
       faces.push_back( myPrevBottomSM->GetSubShape() );
 
     TopExp_Explorer faceIt( mesh->GetShapeToMesh(), TopAbs_FACE );
@@ -1426,7 +1623,7 @@ bool StdMeshers_Prism_3D::computeBase(const Prism_3D::TPrismTopo& thePrism)
           while ( smIt->more() && subOK )
           {
             SMESH_subMesh* sub = smIt->next();
-            sub->ComputeStateEngine( SMESH_subMesh::COMPUTE );
+            sub->ComputeStateEngine( SMESH_subMesh::COMPUTE_SUBMESH );
             subOK = sub->IsMeshComputed();
           }
           if ( !subOK )
@@ -1434,23 +1631,31 @@ bool StdMeshers_Prism_3D::computeBase(const Prism_3D::TPrismTopo& thePrism)
         }
         try {
           OCC_CATCH_SIGNALS;
+
+          Hypothesis_Status status;
+          algo->CheckHypothesis( *mesh, faces[i], status );
           algo->InitComputeError();
-          algo->Compute( *mesh, botSM->GetSubShape() );
+          if ( algo->Compute( *mesh, botSM->GetSubShape() ))
+          {
+            myPrevBottomSM = thePrism.myAlgoSM = mesh->GetSubMesh( faces[i] );
+            break;
+          }
         }
         catch (...) {
         }
       }
     }
   }
+  else
+  {
+    myPrevBottomSM = thePrism.myAlgoSM = botSM;
+  }
 
   if ( botSM->IsEmpty() )
     return error( COMPERR_BAD_INPUT_MESH,
                   TCom( "No mesher defined to compute the base face #")
                   << shapeID( thePrism.myBottom ));
 
-  if ( botSM->GetAlgo() )
-    myPrevBottomSM = botSM;
-
   return true;
 }
 
@@ -1465,8 +1670,8 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism)
   SMESHDS_Mesh* meshDS = myHelper->GetMeshDS();
   DBGOUT( endl << "COMPUTE Prism " << meshDS->ShapeToIndex( thePrism.myShape3D ));
 
-  TProjction1dAlgo*      projector1D = TProjction1dAlgo::instance( this );
-  StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this, myHelper );
+  TProjction1dAlgo* projector1D = TProjction1dAlgo::instance( this );
+  TQuadrangleAlgo*     quadAlgo = TQuadrangleAlgo::instance( this, myHelper );
 
   // SMESH_HypoFilter hyp1dFilter( SMESH_HypoFilter::IsAlgo(),/*not=*/true);
   // hyp1dFilter.And( SMESH_HypoFilter::HasDim( 1 ));
@@ -1544,7 +1749,7 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism)
       }
 
       // assure that all the source (left) EDGEs are meshed
-      int nbSrcSegments = 0;
+      smIdType nbSrcSegments = 0;
       for ( int i = 0; i < lftSide->NbEdges(); ++i )
       {
         if ( isArtificialQuad )
@@ -1636,6 +1841,8 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism)
           mesh->GetSubMesh( v )->ComputeStateEngine( SMESH_subMesh::COMPUTE );
           const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, meshDS );
           newNodes[ is2ndV ? newNodes.size()-1 : 0 ] = (SMDS_MeshNode*) n;
+          if ( !n )
+            return toSM( error( TCom("No node on vertex #") << meshDS->ShapeToIndex( v )));
         }
 
         // compute nodes on target EDGEs
@@ -1939,9 +2146,9 @@ bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh&         theMesh,
     if( anIt==aResMap.end() )
       return toSM( error( "Submesh can not be evaluated"));
 
-    std::vector<int> aVec = (*anIt).second;
-    int nbtri = Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]);
-    int nbqua = Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
+    std::vector<smIdType> aVec = (*anIt).second;
+    smIdType nbtri = std::max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]);
+    smIdType nbqua = std::max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
     if( nbtri==0 && nbqua>0 ) {
       NbQFs++;
     }
@@ -1951,7 +2158,7 @@ bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh&         theMesh,
   }
 
   if(NbQFs<4) {
-    std::vector<int> aResVec(SMDSEntity_Last);
+    std::vector<smIdType> aResVec(SMDSEntity_Last);
     for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
     SMESH_subMesh * sm = theMesh.GetSubMesh(theShape);
     aResMap.insert(std::make_pair(sm,aResVec));
@@ -1961,7 +2168,7 @@ bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh&         theMesh,
   if(NumBase==0) NumBase = 1; // only quads => set 1 faces as base
 
   // find number of 1d elems for base face
-  int nb1d = 0;
+  smIdType nb1d = 0;
   TopTools_MapOfShape Edges1;
   for (TopExp_Explorer exp(aFaces.Value(NumBase), TopAbs_EDGE); exp.More(); exp.Next()) {
     Edges1.Add(exp.Current());
@@ -1969,8 +2176,8 @@ bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh&         theMesh,
     if( sm ) {
       MapShapeNbElemsItr anIt = aResMap.find(sm);
       if( anIt == aResMap.end() ) continue;
-      std::vector<int> aVec = (*anIt).second;
-      nb1d += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
+      std::vector<smIdType> aVec = (*anIt).second;
+      nb1d += std::max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
     }
   }
   // find face opposite to base face
@@ -1990,25 +2197,25 @@ bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh&         theMesh,
     }
   }
   // find number of 2d elems on side faces
-  int nb2d = 0;
+  smIdType nb2d = 0;
   for(i=1; i<=6; i++) {
     if( i==OppNum || i==NumBase ) continue;
     MapShapeNbElemsItr anIt = aResMap.find( meshFaces[i-1] );
     if( anIt == aResMap.end() ) continue;
-    std::vector<int> aVec = (*anIt).second;
-    nb2d += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
+    std::vector<smIdType> aVec = (*anIt).second;
+    nb2d += std::max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
   }
 
   MapShapeNbElemsItr anIt = aResMap.find( meshFaces[NumBase-1] );
-  std::vector<int> aVec = (*anIt).second;
+  std::vector<smIdType> aVec = (*anIt).second;
   bool IsQuadratic = (aVec[SMDSEntity_Quad_Triangle]>aVec[SMDSEntity_Triangle]) ||
                      (aVec[SMDSEntity_Quad_Quadrangle]>aVec[SMDSEntity_Quadrangle]);
-  int nb2d_face0_3 = Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]);
-  int nb2d_face0_4 = Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
-  int nb0d_face0 = aVec[SMDSEntity_Node];
-  int nb1d_face0_int = ( nb2d_face0_3*3 + nb2d_face0_4*4 - nb1d ) / 2;
+  smIdType nb2d_face0_3 = std::max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]);
+  smIdType nb2d_face0_4 = std::max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
+  smIdType nb0d_face0 = aVec[SMDSEntity_Node];
+  smIdType nb1d_face0_int = ( nb2d_face0_3*3 + nb2d_face0_4*4 - nb1d ) / 2;
 
-  std::vector<int> aResVec(SMDSEntity_Last);
+  std::vector<smIdType> aResVec(SMDSEntity_Last);
   for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
   if(IsQuadratic) {
     aResVec[SMDSEntity_Quad_Penta] = nb2d_face0_3 * ( nb2d/nb1d );
@@ -2222,10 +2429,11 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf
         {
           for ( int iE = 0; iE < botSide->NbEdges(); ++iE )
           {
+            // sides are CWW oriented
             NSProjUtils::InsertAssociation( botSide->Edge( iE ),
                                             topSide->Edge( iE ), shape2ShapeMap );
-            NSProjUtils::InsertAssociation( myHelper->IthVertex( 0, botSide->Edge( iE )),
-                                            myHelper->IthVertex( 0, topSide->Edge( iE )),
+            NSProjUtils::InsertAssociation( botSide->FirstVertex( iE ),
+                                            topSide->LastVertex ( iE ),
                                             shape2ShapeMap );
           }
         }
@@ -2276,7 +2484,7 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf
 
   // Fill myBotToColumnMap
 
-  int zSize = myBlock.VerticalSize();
+  size_t zSize = myBlock.VerticalSize();
   TNodeNodeMap::const_iterator bN_tN = n2nMapPtr->begin();
   for ( ; bN_tN != n2nMapPtr->end(); ++bN_tN )
   {
@@ -2348,7 +2556,7 @@ bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf &             bottom
 
   // Fill myBotToColumnMap
 
-  int zSize = myBlock.VerticalSize();
+  size_t zSize = myBlock.VerticalSize();
   Prism_3D::TNode prevTNode;
   SMDS_NodeIteratorPtr nIt = botSMDS->GetNodes();
   while ( nIt->more() )
@@ -2674,6 +2882,9 @@ bool StdMeshers_Prism_3D::allVerticalEdgesStraight( const Prism_3D::TPrismTopo&
 bool StdMeshers_Prism_3D::project2dMesh(const TopoDS_Face& theSrcFace,
                                         const TopoDS_Face& theTgtFace)
 {
+  if ( CountEdges( theSrcFace ) != CountEdges( theTgtFace ))
+    return false;
+
   TProjction2dAlgo* projector2D = TProjction2dAlgo::instance( this );
   projector2D->myHyp.SetSourceFace( theSrcFace );
   bool ok = projector2D->Compute( *myHelper->GetMesh(), theTgtFace );
@@ -2705,7 +2916,7 @@ bool StdMeshers_Prism_3D::project2dMesh(const TopoDS_Face& theSrcFace,
  */
 //================================================================================
 
-bool StdMeshers_Prism_3D::setFaceAndEdgesXYZ( const int faceID, const gp_XYZ& params, int z )
+bool StdMeshers_Prism_3D::setFaceAndEdgesXYZ( const int faceID, const gp_XYZ& params, int /*z*/ )
 {
   // find base and top edges of the face
   enum { BASE = 0, TOP, LEFT, RIGHT };
@@ -2771,19 +2982,50 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable()
 {
   struct EdgeWithNeighbors
   {
-    TopoDS_Edge _edge;
-    int         _iBase;   /* index in a WIRE with non-base EDGEs excluded */
-    int         _iL, _iR; /* used to connect edges in a base FACE */
-    bool        _isBase;  /* is used in a base FACE */
-    EdgeWithNeighbors(const TopoDS_Edge& E, int iE, int nbE, int shift, bool isBase ):
-      _edge( E ), _iBase( iE + shift ),
-      _iL( SMESH_MesherHelper::WrapIndex( iE-1, Max( 1, nbE )) + shift ),
-      _iR( SMESH_MesherHelper::WrapIndex( iE+1, Max( 1, nbE )) + shift ),
+    TopoDS_Edge   _edge;
+    int           _iBase;     // index in a WIRE with non-base EDGEs excluded
+    int           _iL, _iR;   // used to connect PrismSide's
+    int           _iE;        // index in a WIRE
+    int           _iLE, _iRE; // used to connect EdgeWithNeighbors's
+    bool          _isBase;    // is used in a base FACE
+    TopoDS_Vertex _vv[2];     // end VERTEXes
+    EdgeWithNeighbors(const TopoDS_Edge& E,
+                      int iE,  int nbE,  int shift,
+                      int iEE, int nbEE, int shiftE,
+                      bool isBase, bool setVV ):
+      _edge( E ),
+      _iBase( iE + shift ),
+      _iL ( SMESH_MesherHelper::WrapIndex( iE-1,  Max( 1, nbE  )) + shift ),
+      _iR ( SMESH_MesherHelper::WrapIndex( iE+1,  Max( 1, nbE  )) + shift ),
+      _iE ( iEE + shiftE ),
+      _iLE( SMESH_MesherHelper::WrapIndex( iEE-1, Max( 1, nbEE )) + shiftE ),
+      _iRE( SMESH_MesherHelper::WrapIndex( iEE+1, Max( 1, nbEE )) + shiftE ),
       _isBase( isBase )
     {
+      if ( setVV )
+      {
+        Vertex( 0 );
+        Vertex( 1 );
+      }
     }
     EdgeWithNeighbors() {}
     bool IsInternal() const { return !_edge.IsNull() && _edge.Orientation() == TopAbs_INTERNAL; }
+    bool IsConnected( const EdgeWithNeighbors& edge, int iEnd ) const
+    {
+      return (( _vv[ iEnd ].IsSame( edge._vv[ 1 - iEnd ])) ||
+              ( IsInternal() && _vv[ iEnd ].IsSame( edge._vv[ iEnd ])));
+    }
+    bool IsConnected( const std::vector< EdgeWithNeighbors > & edges, int iEnd ) const
+    {
+      int iEdge = iEnd ? _iRE : _iLE;
+      return iEdge == _iE ? false : IsConnected( edges[ iEdge ], iEnd );
+    }
+    const TopoDS_Vertex& Vertex( int iEnd )
+    {
+      if ( _vv[ iEnd ].IsNull() )
+        _vv[ iEnd ] = SMESH_MesherHelper::IthVertex( iEnd, _edge );
+      return _vv[ iEnd ];
+    }
   };
   // PrismSide contains all FACEs linking a bottom EDGE with a top one.
   struct PrismSide
@@ -2798,8 +3040,8 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable()
     PrismSide                  *_leftSide;       // neighbor sides
     PrismSide                  *_rightSide;
     bool                        _isInternal; // whether this side raises from an INTERNAL EDGE
-    void SetExcluded() { _leftSide = _rightSide = NULL; }
-    bool IsExcluded() const { return !_leftSide; }
+    //void SetExcluded() { _leftSide = _rightSide = NULL; }
+    //bool IsExcluded() const { return !_leftSide; }
     const TopoDS_Edge& Edge( int i ) const
     {
       return (*_edges)[ i ]._edge;
@@ -2810,14 +3052,33 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable()
         if ( E.IsSame( Edge( i ))) return i;
       return -1;
     }
-    bool IsSideFace( const TopoDS_Shape& face, const bool checkNeighbors ) const
+    const TopoDS_Vertex& Vertex( int iE, int iEnd ) const
     {
-      if ( _faces->Contains( face )) // avoid returning true for a prism top FACE
-        return ( !_face.IsNull() || !( face.IsSame( _faces->FindKey( _faces->Extent() ))));
-
+      return (*_edges)[ iE ].Vertex( iEnd );
+    }
+    bool HasVertex( const TopoDS_Vertex& V ) const
+    {
+      for ( size_t i = 0; i < _edges->size(); ++i )
+        if ( V.IsSame( Vertex( i, 0 ))) return true;
+      return false;
+    }
+    bool IsSideFace( const TopTools_ListOfShape& faces,
+                     const TopoDS_Face&          avoidFace,
+                     const bool                  checkNeighbors ) const
+    {
+      TopTools_ListIteratorOfListOfShape faceIt( faces );
+      for ( ; faceIt.More(); faceIt.Next() )
+      {
+        const TopoDS_Shape& face = faceIt.Value();
+        if ( !face.IsSame( avoidFace ))
+        {
+          if ( _faces->Contains( face )) // avoid returning true for a prism top FACE
+            return ( !_face.IsNull() || !( face.IsSame( _faces->FindKey( _faces->Extent() ))));
+        }
+      }
       if ( checkNeighbors )
-        return (( _leftSide  && _leftSide->IsSideFace ( face, false )) ||
-                ( _rightSide && _rightSide->IsSideFace( face, false )));
+        return (( _leftSide  && _leftSide->IsSideFace ( faces, avoidFace, false )) ||
+                ( _rightSide && _rightSide->IsSideFace( faces, avoidFace, false )));
 
       return false;
     }
@@ -2827,20 +3088,39 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable()
    * \brief Return another faces sharing an edge
    */
   const TopoDS_Face & getAnotherFace( const TopoDS_Face& face,
-                                      const TopoDS_Edge& edge,
-                                      TopTools_IndexedDataMapOfShapeListOfShape& facesOfEdge)
+                                      const TopTools_ListOfShape& faces)
   {
-    TopTools_ListIteratorOfListOfShape faceIt( facesOfEdge.FindFromKey( edge ));
+    TopTools_ListIteratorOfListOfShape faceIt( faces );
     for ( ; faceIt.More(); faceIt.Next() )
       if ( !face.IsSame( faceIt.Value() ))
         return TopoDS::Face( faceIt.Value() );
     return face;
   }
+  //--------------------------------------------------------------------------------
+  /*!
+   * \brief Return another faces sharing an edge
+   */
+  const TopoDS_Face & getAnotherFace( const TopoDS_Face& face,
+                                      const TopoDS_Edge& edge,
+                                      TopTools_IndexedDataMapOfShapeListOfShape& facesOfEdge)
+  {
+    return getAnotherFace( face, facesOfEdge.FindFromKey( edge ));
+  }
 
   //--------------------------------------------------------------------------------
   /*!
    * \brief Return ordered edges of a face
    */
+  //================================================================================
+  /*!
+   * \brief Return ordered edges of a face
+   *  \param [in] face - the face
+   *  \param [out] edges - return edge (edges from which no vertical faces raise excluded)
+   *  \param [in] facesOfEdge - faces of each edge
+   *  \param [in] noHolesAllowed - are multiple wires allowed
+   */
+  //================================================================================
+
   bool getEdges( const TopoDS_Face&                         face,
                  vector< EdgeWithNeighbors > &              edges,
                  TopTools_IndexedDataMapOfShapeListOfShape& facesOfEdge,
@@ -2856,11 +3136,10 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable()
     if ( nbW > 1 && noHolesAllowed )
       return false;
 
-    int iE, nbTot = 0, nbBase, iBase;
     list< TopoDS_Edge >::iterator   e = ee.begin();
     list< int         >::iterator nbE = nbEdgesInWires.begin();
     for ( ; nbE != nbEdgesInWires.end(); ++nbE )
-      for ( iE = 0; iE < *nbE; ++e, ++iE )
+      for ( int iE = 0; iE < *nbE; ++e, ++iE )
         if ( SMESH_Algo::isDegenerated( *e )) // degenerated EDGE is never used
         {
           e = --ee.erase( e );
@@ -2868,6 +3147,7 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable()
           --iE;
         }
 
+    int iE, nbTot = 0, iBase, nbBase, nbTotBase = 0;
     vector<int> isBase;
     edges.clear();
     e = ee.begin();
@@ -2883,40 +3163,51 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable()
       }
       for ( iBase = 0, iE = 0; iE < *nbE; ++e, ++iE )
       {
-        edges.push_back( EdgeWithNeighbors( *e, iBase, nbBase, nbTot, isBase[ iE ] ));
+        edges.push_back( EdgeWithNeighbors( *e,
+                                            iBase, nbBase, nbTotBase,
+                                            iE,    *nbE,   nbTot,
+                                            isBase[ iE ], nbW > 1 ));
         iBase += isBase[ iE ];
       }
-      nbTot += nbBase;
+      nbTot     += *nbE;
+      nbTotBase += nbBase;
     }
-    if ( nbTot == 0 )
+    if ( nbTotBase == 0 )
       return false;
 
-    // IPAL53099. Set correct neighbors to INTERNAL EDGEs, which can be connected to
-    // EDGEs of the outer WIRE but this fact can't be detected by their order.
+    // IPAL53099, 54416. Set correct neighbors to INTERNAL EDGEs
     if ( nbW > 1 )
     {
       int iFirst = 0, iLast;
       for ( nbE = nbEdgesInWires.begin(); nbE != nbEdgesInWires.end(); ++nbE )
       {
         iLast = iFirst + *nbE - 1;
-        TopoDS_Vertex vv[2] = { SMESH_MesherHelper::IthVertex( 0, edges[ iFirst ]._edge ),
-                                SMESH_MesherHelper::IthVertex( 1, edges[ iLast  ]._edge ) };
-        bool isConnectOk = ( vv[0].IsSame( vv[1] ));
+        bool isConnectOk = ( edges[ iFirst ].IsConnected( edges, 0 ) &&
+                             edges[ iFirst ].IsConnected( edges, 1 ));
         if ( !isConnectOk )
         {
-          edges[ iFirst ]._iL = edges[ iFirst ]._iBase; // connect to self
-          edges[ iLast  ]._iR = edges[ iLast ]._iBase;
-
-          // look for an EDGE of the outer WIREs connected to vv
-          TopoDS_Vertex v0, v1;
-          for ( iE = 0; iE < iFirst; ++iE )
+          for ( iE = iFirst; iE <= iLast; ++iE )
           {
-            v0 = SMESH_MesherHelper::IthVertex( 0, edges[ iE ]._edge );
-            v1 = SMESH_MesherHelper::IthVertex( 1, edges[ iE ]._edge );
-            if ( vv[0].IsSame( v0 ) || vv[0].IsSame( v1 ))
-              edges[ iFirst ]._iL = edges[ iE ]._iBase;
-            if ( vv[1].IsSame( v0 ) || vv[1].IsSame( v1 ))
-              edges[ iLast  ]._iR = edges[ iE ]._iBase;
+            if ( !edges[ iE ]._isBase )
+              continue;
+            int* iNei[] = { & edges[ iE ]._iL,
+                            & edges[ iE ]._iR };
+            for ( int iV = 0; iV < 2; ++iV )
+            {
+              if ( edges[ iE ].IsConnected( edges, iV ))
+                continue; // Ok - connected to a neighbor EDGE
+
+              // look for a connected EDGE
+              bool found = false;
+              for ( int iE2 = 0, nbE = edges.size(); iE2 < nbE &&   !found; ++iE2 )
+                if (( iE2 != iE ) &&
+                    ( found = edges[ iE ].IsConnected( edges[ iE2 ], iV )))
+                {
+                  *iNei[ iV ] = edges[ iE2 ]._iBase;
+                }
+              if ( !found )
+                *iNei[ iV ] = edges[ iE ]._iBase; // connect to self
+            }
           }
         }
         iFirst += *nbE;
@@ -3049,11 +3340,11 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA
       }
 
       bool isOK = true; // ok for a current botF
-      bool isAdvanced = true; // is new data found in a current loop
+      bool hasAdvanced = true; // is new data found in a current loop
       int  nbFoundSideFaces = 0;
-      for ( int iLoop = 0; isOK && isAdvanced; ++iLoop )
+      for ( int iLoop = 0; isOK && hasAdvanced; ++iLoop )
       {
-        isAdvanced = false;
+        hasAdvanced = false;
         for ( size_t iS = 0; iS < sides.size() && isOK; ++iS )
         {
           PrismSide& side = sides[ iS ];
@@ -3065,19 +3356,32 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA
             // find vertical EDGEs --- EDGEs shared with neighbor side FACEs
             for ( int is2nd = 0; is2nd < 2 && isOK; ++is2nd ) // 2 adjacent neighbors
             {
-              int di = is2nd ? 1 : -1;
               const PrismSide* adjSide = is2nd ? side._rightSide : side._leftSide;
+              if ( side._isInternal )
+              {
+                const TopoDS_Vertex& V = side.Vertex( side._iBotEdge, is2nd );
+                bool lHasV = side._leftSide ->HasVertex( V );
+                bool rHasV = side._rightSide->HasVertex( V );
+                if ( lHasV == rHasV )
+                  adjSide = ( &side == side._leftSide ) ? side._rightSide : side._leftSide;
+                else
+                  adjSide = ( rHasV ) ? side._rightSide : side._leftSide;
+              }
+              int di = is2nd ? 1 : -1;
               for ( size_t i = 1; i < side._edges->size(); ++i )
               {
                 int iE = SMESH_MesherHelper::WrapIndex( i*di + side._iBotEdge, side._edges->size());
                 if ( side._isCheckedEdge[ iE ] ) continue;
-                const TopoDS_Edge&      vertE = side.Edge( iE );
-                const TopoDS_Shape& neighborF = getAnotherFace( side._face, vertE, facesOfEdge );
-                bool isEdgeShared = (( adjSide->IsSideFace( neighborF, side._isInternal )) ||
-                                     ( adjSide == &side && neighborF.IsSame( side._face )) );
+                const TopoDS_Edge&               vertE = side.Edge( iE );
+                const TopTools_ListOfShape& neighborFF = facesOfEdge.FindFromKey( vertE );
+                bool isEdgeShared = (( adjSide->IsSideFace( neighborFF, side._face,
+                                                            side._isInternal )) ||
+                                     ( adjSide == &side &&
+                                       side._face.IsSame( getAnotherFace( side._face,
+                                                                          neighborFF ))));
                 if ( isEdgeShared ) // vertE is shared with adjSide
                 {
-                  isAdvanced = true;
+                  hasAdvanced = true;
                   side._isCheckedEdge[ iE ] = true;
                   side._nbCheckedEdges++;
                   int nbNotCheckedE = side._edges->size() - side._nbCheckedEdges;
@@ -3145,7 +3449,7 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA
             const int nbE = side._edges->size();
             if ( nbE >= 4 )
             {
-              isAdvanced = true;
+              hasAdvanced = true;
               ++nbFoundSideFaces;
               side._iBotEdge = side.FindEdge( side._topEdge );
               side._isCheckedEdge.clear();
@@ -3175,7 +3479,7 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA
           cerr << "BUG: infinite loop in StdMeshers_Prism_3D::IsApplicable()" << endl;
 #endif
         }
-      } // while isAdvanced
+      } // while hasAdvanced
 
       if ( isOK && sides[0]._faces->Extent() > 1 )
       {
@@ -3186,12 +3490,20 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA
         }
         else
         {
+          // check that all face columns end up at the same top face
           const TopoDS_Shape& topFace = sides[0]._faces->FindKey( nbFaces );
           size_t iS;
           for ( iS = 1; iS < sides.size(); ++iS )
             if ( ! sides[ iS ]._faces->Contains( topFace ))
               break;
-          prismDetected = ( iS == sides.size() );
+          if (( prismDetected = ( iS == sides.size() )))
+          {
+            // check that bottom and top faces has equal nb of edges
+            TEdgeWithNeighborsVec& topEdges = faceEdgesVec[ allFaces.FindIndex( topFace )];
+            if ( topEdges.empty() )
+              getEdges( TopoDS::Face( topFace ), topEdges, facesOfEdge, /*noHoles=*/false );
+            prismDetected = ( botEdges.size() == topEdges.size() );
+          }
         }
       }
     } // loop on allFaces
@@ -3238,6 +3550,7 @@ namespace Prism_3D
     myBottomEdges.clear();
     myNbEdgesInWires.clear();
     myWallQuads.clear();
+    myAlgoSM = nullptr;
   }
 
   //================================================================================
@@ -3598,7 +3911,7 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper*         helper,
         return error(COMPERR_BAD_INPUT_MESH, TCom("Can't find regular quadrangle mesh ")
                      << "on a side face #" << MeshDS()->ShapeToIndex( (*quad)->face ));
     }
-    if ( !faceColumns.empty() && (int)faceColumns.begin()->second.size() != VerticalSize() )
+    if ( !faceColumns.empty() && faceColumns.begin()->second.size() != VerticalSize() )
       return error(COMPERR_BAD_INPUT_MESH, "Different 'vertical' discretization");
 
     // edge columns
@@ -3914,7 +4227,7 @@ bool StdMeshers_PrismAsBlock::GetLayersTransformation(vector<gp_Trsf> &
                                                       const Prism_3D::TPrismTopo& prism) const
 {
   const bool itTopMeshed = !SubMesh( ID_BOT_FACE )->IsEmpty();
-  const int zSize = VerticalSize();
+  const size_t zSize = VerticalSize();
   if ( zSize < 3 && !itTopMeshed ) return true;
   trsf.resize( zSize - 1 );
 
@@ -3961,7 +4274,7 @@ bool StdMeshers_PrismAsBlock::GetLayersTransformation(vector<gp_Trsf> &
   gp_Ax3 cs0 = getLayerCoordSys(0, columns, xCol );
   //double dist0 = cs0.Location().Distance( gpXYZ( (*columns[0])[0]));
   toCs0.SetTransformation( cs0 );
-  for ( int z = 1; z < zSize; ++z )
+  for ( size_t z = 1; z < zSize; ++z )
   {
     gp_Ax3 csZ = getLayerCoordSys(z, columns, xCol );
     //double distZ = csZ.Location().Distance( gpXYZ( (*columns[0])[z]));
@@ -3989,10 +4302,10 @@ bool StdMeshers_PrismAsBlock::GetLayersTransformation(vector<gp_Trsf> &
 
 //================================================================================
 /*!
- * \brief Check curve orientation of a bootom edge
+ * \brief Check curve orientation of a bottom edge
   * \param meshDS - mesh DS
   * \param columnsMap - node columns map of side face
-  * \param bottomEdge - the bootom edge
+  * \param bottomEdge - the bottom edge
   * \param sideFaceID - side face in-block ID
   * \retval bool - true if orientation coincide with in-block forward orientation
  */
@@ -4065,7 +4378,9 @@ void StdMeshers_PrismAsBlock::faceGridToPythonDump(const SMESH_Block::TShapeID f
            << n << ", " << n+1 << ", "
            << n+nb+2 << ", " << n+nb+1 << "]) " << endl;
     }
-
+#else
+  (void)face; // unused in release mode
+  (void)nb;   // unused in release mode
 #endif
 }
 
@@ -4540,7 +4855,7 @@ TopoDS_Edge StdMeshers_PrismAsBlock::TSideFace::GetEdge(const int iEdge) const
       column = & ( myParamToColumnMap->rbegin()->second );
     else
       column = & ( myParamToColumnMap->begin()->second );
-    if ( column->size() > 0 )
+    if ( column->size() > 1 )
       edge = myHelper.GetSubShapeByNode( (*column)[ 1 ], meshDS );
     if ( edge.IsNull() || edge.ShapeType() == TopAbs_VERTEX )
       node = column->front();
@@ -4685,6 +5000,8 @@ void StdMeshers_PrismAsBlock::TSideFace::dumpNodes(int nbNodes) const
   TVerticalEdgeAdaptor* vSide1 = (TVerticalEdgeAdaptor*) VertiCurve(1);
   cout << "Verti side 1: "; vSide1->dumpNodes(nbNodes); cout << endl;
   delete hSize0; delete hSize1; delete vSide0; delete vSide1;
+#else
+  (void)nbNodes; // unused in release mode
 #endif
 }
 
@@ -4731,6 +5048,8 @@ void StdMeshers_PrismAsBlock::TVerticalEdgeAdaptor::dumpNodes(int nbNodes) const
     cout << (*myNodeColumn)[i]->GetID() << " ";
   if ( nbNodes < (int) myNodeColumn->size() )
     cout << myNodeColumn->back()->GetID();
+#else
+  (void)nbNodes; // unused in release mode
 #endif
 }
 
@@ -4789,6 +5108,8 @@ void StdMeshers_PrismAsBlock::THorizontalEdgeAdaptor::dumpNodes(int nbNodes) con
   side->GetColumns( u , col, col2 );
   if ( n != col->second[ i ] )
     cout << col->second[ i ]->GetID();
+#else
+  (void)nbNodes; // unused in release mode
 #endif
 }
 
@@ -5121,10 +5442,10 @@ bool StdMeshers_Sweeper::ComputeNodesByTrsf( const double tol,
     for ( ++zS, --zT; zS < zTgt; ++zS, --zT ) // vertical loop on layers
     {
       // invert transformation
-      if ( !trsfOfLayer[ zS+1 ].Invert() )
-        trsfOfLayer[ zS+1 ] = NSProjUtils::TrsfFinder3D(); // to recompute
-      if ( !trsfOfLayer[ zT-1 ].Invert() )
-        trsfOfLayer[ zT-1 ] = NSProjUtils::TrsfFinder3D();
+      //if ( !trsfOfLayer[ zS+1 ].Invert() )
+      trsfOfLayer[ zS+1 ] = NSProjUtils::TrsfFinder3D(); // to recompute
+      //if ( !trsfOfLayer[ zT-1 ].Invert() )
+      trsfOfLayer[ zT-1 ] = NSProjUtils::TrsfFinder3D();
 
       // project internal nodes and compute bnd error
       for ( size_t iP = 0; iP < myBndColumns.size(); ++iP )
@@ -5294,7 +5615,7 @@ bool StdMeshers_Sweeper::ComputeNodesOnStraight()
   int    botTriaNodes[3], topTriaNodes[3];
   bool   checkUV = true;
 
-  int nbInternalNodes = myIntColumns.size();
+  size_t nbInternalNodes = myIntColumns.size();
   myBotDelaunay->InitTraversal( nbInternalNodes );
 
   while (( botNode = myBotDelaunay->NextNode( botBC, botTriaNodes )))
@@ -5363,15 +5684,34 @@ void StdMeshers_Sweeper::fillZColumn( TZColumn&    zColumn,
 
 void StdMeshers_Sweeper::prepareTopBotDelaunay()
 {
+  SMESH_MesherHelper* helper[2] = { myHelper, myHelper };
+  SMESH_MesherHelper botHelper( *myHelper->GetMesh() );
+  SMESH_MesherHelper topHelper( *myHelper->GetMesh() );
+  const SMDS_MeshNode* intBotNode = 0;
+  const SMDS_MeshNode* intTopNode = 0;
+  if ( myHelper->HasSeam() || myHelper->HasDegeneratedEdges() ) // use individual helpers
+  {
+    botHelper.SetSubShape( myBotFace );
+    topHelper.SetSubShape( myTopFace );
+    helper[0] = & botHelper;
+    helper[1] = & topHelper;
+    if ( !myIntColumns.empty() )
+    {
+      TNodeColumn& nodes = *myIntColumns[ myIntColumns.size()/2 ];
+      intBotNode = nodes[0];
+      intTopNode = nodes.back();
+    }
+  }
+
   UVPtStructVec botUV( myBndColumns.size() );
   UVPtStructVec topUV( myBndColumns.size() );
   for ( size_t i = 0; i < myBndColumns.size(); ++i )
   {
     TNodeColumn& nodes = *myBndColumns[i];
     botUV[i].node = nodes[0];
-    botUV[i].SetUV( myHelper->GetNodeUV( myBotFace, nodes[0] ));
+    botUV[i].SetUV( helper[0]->GetNodeUV( myBotFace, nodes[0], intBotNode ));
     topUV[i].node = nodes.back();
-    topUV[i].SetUV( myHelper->GetNodeUV( myTopFace, nodes.back() ));
+    topUV[i].SetUV( helper[1]->GetNodeUV( myTopFace, nodes.back(), intTopNode ));
     botUV[i].node->setIsMarked( true );
   }
   TopoDS_Edge dummyE;
@@ -5424,7 +5764,7 @@ bool StdMeshers_Sweeper::findDelaunayTriangles()
   TopBotTriangles          tbTrias;
   bool  checkUV = true;
 
-  int nbInternalNodes = myIntColumns.size();
+  size_t nbInternalNodes = myIntColumns.size();
   myTopBotTriangles.resize( nbInternalNodes );
 
   myBotDelaunay->InitTraversal( nbInternalNodes );