Salome HOME
Regression of SALOME_TESTS/Grids/smesh/imps_09/K2
[modules/smesh.git] / src / StdMeshers / StdMeshers_Prism_3D.cxx
index 07e9a166d838772b7633130ec1f1613038a434ed..579cbe55011420ac9c6d1725381b2e59bdcaf906 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2014  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
@@ -6,7 +6,7 @@
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 // License as published by the Free Software Foundation; either
-// version 2.1 of the License.
+// version 2.1 of the License, or (at your option) any later version.
 //
 // This library is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -107,7 +107,7 @@ namespace {
            algo->myProxyMesh->GetMesh() != helper->GetMesh() )
         algo->myProxyMesh.reset( new SMESH_ProxyMesh( *helper->GetMesh() ));
 
-      algo->myQuadStruct.reset();
+      algo->myQuadList.clear();
 
       if ( helper )
         algo->_quadraticMesh = helper->GetIsQuadratic();
@@ -157,6 +157,46 @@ namespace {
       return algo;
     }
   };
+  //=======================================================================
+  /*!
+   * \brief Returns already computed EDGEs
+   */
+  void getPrecomputedEdges( SMESH_MesherHelper&    theHelper,
+                            const TopoDS_Shape&    theShape,
+                            vector< TopoDS_Edge >& theEdges)
+  {
+    theEdges.clear();
+
+    SMESHDS_Mesh* meshDS = theHelper.GetMeshDS();
+    SMESHDS_SubMesh* sm;
+
+    TopTools_IndexedMapOfShape edges;
+    TopExp::MapShapes( theShape, TopAbs_EDGE, edges );
+    for ( int iE = 1; iE <= edges.Extent(); ++iE )
+    {
+      const TopoDS_Shape edge = edges( iE );
+      if (( ! ( sm = meshDS->MeshElements( edge ))) ||
+          ( sm->NbElements() == 0 ))
+        continue;
+
+      // there must not be FACEs meshed with triangles and sharing a computed EDGE
+      // as the precomputed EDGEs are used for propagation other to 'vertical' EDGEs
+      bool faceFound = false;
+      PShapeIteratorPtr faceIt =
+        theHelper.GetAncestors( edge, *theHelper.GetMesh(), TopAbs_FACE );
+      while ( const TopoDS_Shape* face = faceIt->next() )
+
+        if (( sm = meshDS->MeshElements( *face )) &&
+            ( sm->NbElements() > 0 ) &&
+            ( !theHelper.IsSameElemGeometry( sm, SMDSGeom_QUADRANGLE ) ))
+        {
+          faceFound;
+          break;
+        }
+      if ( !faceFound )
+        theEdges.push_back( TopoDS::Edge( edge ));
+    }
+  }
 
   //================================================================================
   /*!
@@ -166,15 +206,15 @@ namespace {
   //================================================================================
 
   bool setBottomEdge( const TopoDS_Edge&   botE,
-                      faceQuadStruct::Ptr& quad,
+                      FaceQuadStruct::Ptr& quad,
                       const TopoDS_Shape&  face)
   {
-    quad->side[ QUAD_TOP_SIDE  ]->Reverse();
-    quad->side[ QUAD_LEFT_SIDE ]->Reverse();
+    quad->side[ QUAD_TOP_SIDE  ].grid->Reverse();
+    quad->side[ QUAD_LEFT_SIDE ].grid->Reverse();
     int edgeIndex = 0;
     for ( size_t i = 0; i < quad->side.size(); ++i )
     {
-      StdMeshers_FaceSide* quadSide = quad->side[i];
+      StdMeshers_FaceSidePtr quadSide = quad->side[i];
       for ( int iE = 0; iE < quadSide->NbEdges(); ++iE )
         if ( botE.IsSame( quadSide->Edge( iE )))
         {
@@ -623,6 +663,21 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
              compute( prism ));
   }
 
+  // find propagation chains from already computed EDGEs
+  vector< TopoDS_Edge > computedEdges;
+  getPrecomputedEdges( helper, theShape, computedEdges );
+  myPropagChains = new TopTools_IndexedMapOfShape[ computedEdges.size() + 1 ];
+  SMESHUtils::ArrayDeleter< TopTools_IndexedMapOfShape > pcDel( myPropagChains );
+  for ( size_t i = 0, nb = 0; i < computedEdges.size(); ++i )
+  {
+    StdMeshers_ProjectionUtils::GetPropagationEdge( &theMesh, TopoDS_Edge(),
+                                                    computedEdges[i], myPropagChains + nb );
+    if ( myPropagChains[ nb ].Extent() < 2 ) // an empty map is a termination sign
+      myPropagChains[ nb ].Clear();
+    else
+      nb++;
+  }
+
   TopTools_MapOfShape meshedSolids;
   list< Prism_3D::TPrismTopo > meshedPrism;
   TopTools_ListIteratorOfListOfShape solidIt;
@@ -650,7 +705,11 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
                !compute( prism ))
             return false;
 
-          meshedFaces.push_front( prism.myTop );
+          SMESHDS_SubMesh* smDS = theMesh.GetMeshDS()->MeshElements( prism.myTop );
+          if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE ))
+          {
+            meshedFaces.push_front( prism.myTop );
+          }
           meshedPrism.push_back( prism );
         }
       }
@@ -681,7 +740,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
               continue; // already computed prism
             }
             // 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 ]->Edge(0);
+            const TopoDS_Edge& wEdge = (*wQuad)->side[ QUAD_TOP_SIDE ].grid->Edge(0);
             PShapeIteratorPtr faceIt = myHelper->GetAncestors( wEdge, *myHelper->GetMesh(),
                                                                TopAbs_FACE);
             while ( const TopoDS_Shape* f = faceIt->next() )
@@ -691,6 +750,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
               prism.myBottom  = candidateF;
               mySetErrorToSM = false;
               if ( !myHelper->IsSubShape( candidateF, prismIt->myShape3D ) &&
+                   myHelper->IsSubShape( candidateF, solid ) &&
                    !myHelper->GetMesh()->GetSubMesh( candidateF )->IsMeshComputed() &&
                    initPrism( prism, solid ) &&
                    project2dMesh( prismIt->myBottom, candidateF))
@@ -698,8 +758,12 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
                 mySetErrorToSM = true;
                 if ( !compute( prism ))
                   return false;
-                meshedFaces.push_front( prism.myTop );
-                meshedFaces.push_front( prism.myBottom );
+                SMESHDS_SubMesh* smDS = theMesh.GetMeshDS()->MeshElements( prism.myTop );
+                if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE ))
+                {
+                  meshedFaces.push_front( prism.myTop );
+                  meshedFaces.push_front( prism.myBottom );
+                }
                 meshedPrism.push_back( prism );
                 meshedSolids.Add( solid );
               }
@@ -879,7 +943,7 @@ bool StdMeshers_Prism_3D::getWallFaces( Prism_3D::TPrismTopo & thePrism,
     int nbKnownFaces;
     do {
       nbKnownFaces = faceMap.Extent();
-      StdMeshers_FaceSide *rightSide, *topSide; // sides of the quad
+      StdMeshers_FaceSidePtr rightSide, topSide; // sides of the quad
       for ( size_t i = 0; i < thePrism.myWallQuads.size(); ++i )
       {
         rightSide = thePrism.myWallQuads[i].back()->side[ QUAD_RIGHT_SIDE ];
@@ -911,8 +975,8 @@ bool StdMeshers_Prism_3D::getWallFaces( Prism_3D::TPrismTopo & thePrism,
     {
       for ( size_t i = 0; i < thePrism.myWallQuads.size(); ++i )
       {
-        StdMeshers_FaceSide* topSide = thePrism.myWallQuads[i].back()->side[ QUAD_TOP_SIDE ];
-        const TopoDS_Edge &     topE = topSide->Edge( 0 );
+        StdMeshers_FaceSidePtr topSide = thePrism.myWallQuads[i].back()->side[ QUAD_TOP_SIDE ];
+        const TopoDS_Edge &       topE = topSide->Edge( 0 );
         if ( topSide->NbEdges() > 1 )
           return toSM( error(COMPERR_BAD_SHAPE, TCom("Side face #") <<
                              shapeID( thePrism.myWallQuads[i].back()->face )
@@ -958,8 +1022,8 @@ bool StdMeshers_Prism_3D::getWallFaces( Prism_3D::TPrismTopo & thePrism,
   // Check that the top FACE shares all the top EDGEs
   for ( size_t i = 0; i < thePrism.myWallQuads.size(); ++i )
   {
-    StdMeshers_FaceSide* topSide = thePrism.myWallQuads[i].back()->side[ QUAD_TOP_SIDE ];
-    const TopoDS_Edge &     topE = topSide->Edge( 0 );
+    StdMeshers_FaceSidePtr topSide = thePrism.myWallQuads[i].back()->side[ QUAD_TOP_SIDE ];
+    const TopoDS_Edge &       topE = topSide->Edge( 0 );
     if ( !myHelper->IsSubShape( topE, thePrism.myTop ))
       return toSM( error( TCom("Wrong source face (#") << shapeID( thePrism.myBottom )));
   }
@@ -1187,7 +1251,7 @@ 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 );
+  TProjction1dAlgo*      projector1D = TProjction1dAlgo::instance( this );
   StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this, myHelper );
 
   SMESH_HypoFilter hyp1dFilter( SMESH_HypoFilter::IsAlgo(),/*not=*/true);
@@ -1205,7 +1269,7 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism)
     int wgt = 0; // "weight"
     for ( ; quad != thePrism.myWallQuads[iW].end(); ++quad )
     {
-      StdMeshers_FaceSide* lftSide = (*quad)->side[ QUAD_LEFT_SIDE ];
+      StdMeshers_FaceSidePtr lftSide = (*quad)->side[ QUAD_LEFT_SIDE ];
       for ( int i = 0; i < lftSide->NbEdges(); ++i )
       {
         ++wgt;
@@ -1224,7 +1288,7 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism)
       quad = thePrism.myWallQuads[iW].begin();
       for ( ; quad != thePrism.myWallQuads[iW].end(); ++quad )
         for ( int i = 0; i < NB_QUAD_SIDES; ++i )
-          (*quad)->side[ i ]->SetIgnoreMediumNodes( true );
+          (*quad)->side[ i ].grid->SetIgnoreMediumNodes( true );
     }
   }
 
@@ -1237,8 +1301,8 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism)
     Prism_3D::TQuadList::const_iterator quad = quads.begin();
     for ( ; quad != quads.end(); ++quad )
     {
-      StdMeshers_FaceSide* rgtSide = (*quad)->side[ QUAD_RIGHT_SIDE ]; // tgt
-      StdMeshers_FaceSide* lftSide = (*quad)->side[ QUAD_LEFT_SIDE ];  // src
+      StdMeshers_FaceSidePtr rgtSide = (*quad)->side[ QUAD_RIGHT_SIDE ]; // tgt
+      StdMeshers_FaceSidePtr lftSide = (*quad)->side[ QUAD_LEFT_SIDE ];  // src
       bool swapLeftRight = ( lftSide->NbSegments( /*update=*/true ) == 0 &&
                              rgtSide->NbSegments( /*update=*/true )  > 0 );
       if ( swapLeftRight )
@@ -1252,8 +1316,17 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism)
         SMESH_subMesh*    srcSM = mesh->GetSubMesh( srcE );
         if ( !srcSM->IsMeshComputed() ) {
           DBGOUT( "COMPUTE V edge " << srcSM->GetId() );
-          srcSM->ComputeSubMeshStateEngine( SMESH_subMesh::COMPUTE );
-          srcSM->ComputeStateEngine       ( SMESH_subMesh::COMPUTE );
+          TopoDS_Edge prpgSrcE = findPropagationSource( srcE );
+          if ( !prpgSrcE.IsNull() ) {
+            srcSM->ComputeSubMeshStateEngine( SMESH_subMesh::COMPUTE );
+            projector1D->myHyp.SetSourceEdge( prpgSrcE );
+            projector1D->Compute( *mesh, srcE );
+            srcSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
+          }
+          else {
+            srcSM->ComputeSubMeshStateEngine( SMESH_subMesh::COMPUTE );
+            srcSM->ComputeStateEngine       ( SMESH_subMesh::COMPUTE );
+          }
           if ( !srcSM->IsMeshComputed() )
             return toSM( error( "Can't compute 1D mesh" ));
         }
@@ -1373,8 +1446,8 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism)
       // to compute stuctured quad mesh on wall FACEs
       // ---------------------------------------------------
       {
-        const TopoDS_Edge& botE = (*quad)->side[ QUAD_BOTTOM_SIDE ]->Edge(0);
-        const TopoDS_Edge& topE = (*quad)->side[ QUAD_TOP_SIDE    ]->Edge(0);
+        const TopoDS_Edge& botE = (*quad)->side[ QUAD_BOTTOM_SIDE ].grid->Edge(0);
+        const TopoDS_Edge& topE = (*quad)->side[ QUAD_TOP_SIDE    ].grid->Edge(0);
         SMESH_subMesh*    botSM = mesh->GetSubMesh( botE );
         SMESH_subMesh*    topSM = mesh->GetSubMesh( topE );
         SMESH_subMesh*    srcSM = botSM;
@@ -1464,6 +1537,21 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism)
   return true;
 }
 
+//=======================================================================
+/*!
+ * \brief Returns a source EDGE of propagation to a given EDGE
+ */
+//=======================================================================
+
+TopoDS_Edge StdMeshers_Prism_3D::findPropagationSource( const TopoDS_Edge& E )
+{
+  for ( size_t i = 0; !myPropagChains[i].IsEmpty(); ++i )
+    if ( myPropagChains[i].Contains( E ))
+      return TopoDS::Edge( myPropagChains[i].FindKey( 1 ));
+
+  return TopoDS_Edge();
+}
+
 //=======================================================================
 //function : Evaluate
 //purpose  : 
@@ -2037,6 +2125,341 @@ int StdMeshers_Prism_3D::shapeID( const TopoDS_Shape& S )
   return myHelper->GetMeshDS()->ShapeToIndex( S );
 }
 
+namespace // utils used by StdMeshers_Prism_3D::IsApplicable()
+{
+  struct EdgeWithNeighbors
+  {
+    TopoDS_Edge _edge;
+    int         _iL, _iR;
+    EdgeWithNeighbors(const TopoDS_Edge& E, int iE, int nbE, int shift = 0 ):
+      _edge( E ),
+      _iL( SMESH_MesherHelper::WrapIndex( iE-1, nbE ) + shift ),
+      _iR( SMESH_MesherHelper::WrapIndex( iE+1, nbE ) + shift )
+    {
+    }
+    EdgeWithNeighbors() {}
+  };
+  struct PrismSide
+  {
+    TopoDS_Face                 _face;
+    TopTools_IndexedMapOfShape *_faces; // pointer because its copy constructor is private
+    TopoDS_Edge                 _topEdge;
+    vector< EdgeWithNeighbors >*_edges;
+    int                         _iBotEdge;
+    vector< bool >              _isCheckedEdge;
+    int                         _nbCheckedEdges; // nb of EDGEs whose location is defined
+    PrismSide                  *_leftSide;
+    PrismSide                  *_rightSide;
+    const TopoDS_Edge& Edge( int i ) const
+    {
+      return (*_edges)[ i ]._edge;
+    }
+    int FindEdge( const TopoDS_Edge& E ) const
+    {
+      for ( size_t i = 0; i < _edges->size(); ++i )
+        if ( E.IsSame( Edge( i ))) return i;
+      return -1;
+    }
+  };
+  //--------------------------------------------------------------------------------
+  /*!
+   * \brief Return ordered edges of a face
+   */
+  bool getEdges( const TopoDS_Face&            face,
+                 vector< EdgeWithNeighbors > & edges,
+                 const bool                    noHolesAllowed)
+  {
+    list< TopoDS_Edge > ee;
+    list< int >         nbEdgesInWires;
+    int nbW = SMESH_Block::GetOrderedEdges( face, ee, nbEdgesInWires );
+    if ( nbW > 1 && noHolesAllowed )
+      return false;
+
+    int iE, nbTot = 0;
+    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 )
+        if ( SMESH_Algo::isDegenerated( *e ))
+        {
+          ee.erase( e );
+          --(*nbE);
+          --iE;
+        }
+        else
+        {
+          e->Orientation( TopAbs_FORWARD ); // for operator==() to work
+        }
+
+    edges.clear();
+    e = ee.begin();
+    for ( nbE = nbEdgesInWires.begin(); nbE != nbEdgesInWires.end(); ++nbE )
+    {
+      for ( iE = 0; iE < *nbE; ++e, ++iE )
+        edges.push_back( EdgeWithNeighbors( *e, iE, *nbE, nbTot ));
+      nbTot += *nbE;
+    }
+    return edges.size();
+  }
+  //--------------------------------------------------------------------------------
+  /*!
+   * \brief Return another faces sharing an edge
+   */
+  const TopoDS_Shape & getAnotherFace( const TopoDS_Face& face,
+                                       const TopoDS_Edge& edge,
+                                       TopTools_IndexedDataMapOfShapeListOfShape& facesOfEdge)
+  {
+    TopTools_ListIteratorOfListOfShape faceIt( facesOfEdge.FindFromKey( edge ));
+    for ( ; faceIt.More(); faceIt.Next() )
+      if ( !face.IsSame( faceIt.Value() ))
+        return faceIt.Value();
+    return face;
+  }
+}
+
+//================================================================================
+/*!
+ * \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 at least one shape is OK
+ */
+//================================================================================
+
+bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckAll)
+{
+  TopExp_Explorer sExp( shape, TopAbs_SOLID );
+  if ( !sExp.More() )
+    return false;
+
+  for ( ; sExp.More(); sExp.Next() )
+  {
+    // check nb shells
+    TopoDS_Shape shell;
+    TopExp_Explorer shExp( sExp.Current(), TopAbs_SHELL );
+    if ( shExp.More() ) {
+      shell = shExp.Current();
+      shExp.Next();
+      if ( shExp.More() )
+        shell.Nullify();
+    }
+    if ( shell.IsNull() ) {
+      if ( toCheckAll ) return false;
+      continue;
+    }
+    // get all faces
+    TopTools_IndexedMapOfShape allFaces;
+    TopExp::MapShapes( shell, TopAbs_FACE, allFaces );
+    if ( allFaces.Extent() < 3 ) {
+      if ( toCheckAll ) return false;
+      continue;
+    }
+    // is a box?
+    if ( allFaces.Extent() == 6 )
+    {
+      TopTools_IndexedMapOfOrientedShape map;
+      bool isBox = SMESH_Block::FindBlockShapes( TopoDS::Shell( shell ),
+                                                 TopoDS_Vertex(), TopoDS_Vertex(), map );
+      if ( isBox ) {
+        if ( !toCheckAll ) return true;
+        continue;
+      }
+    }
+#ifdef _DEBUG_
+    TopTools_IndexedMapOfShape allShapes;
+    TopExp::MapShapes( shape, allShapes );
+#endif
+
+    TopTools_IndexedDataMapOfShapeListOfShape facesOfEdge;
+    TopTools_ListIteratorOfListOfShape faceIt;
+    TopExp::MapShapesAndAncestors( sExp.Current(), TopAbs_EDGE, TopAbs_FACE , facesOfEdge );
+    if ( facesOfEdge.IsEmpty() ) {
+      if ( toCheckAll ) return false;
+      continue;
+    }
+
+    typedef vector< EdgeWithNeighbors > TEdgeWithNeighborsVec;
+    vector< TEdgeWithNeighborsVec > faceEdgesVec( allFaces.Extent() + 1 );
+    TopTools_IndexedMapOfShape* facesOfSide = new TopTools_IndexedMapOfShape[ faceEdgesVec.size() ];
+    SMESHUtils::ArrayDeleter<TopTools_IndexedMapOfShape> delFacesOfSide( facesOfSide );
+
+    // try to use each face as a bottom one
+    bool prismDetected = false;
+    for ( int iF = 1; iF < allFaces.Extent() && !prismDetected; ++iF )
+    {
+      const TopoDS_Face& botF = TopoDS::Face( allFaces( iF ));
+
+      TEdgeWithNeighborsVec& botEdges = faceEdgesVec[ iF ];
+      if ( botEdges.empty() )
+      {
+        if ( !getEdges( botF, botEdges, /*noHoles=*/false ))
+          break;
+        if ( allFaces.Extent()-1 <= (int) botEdges.size() )
+          continue; // all faces are adjacent to botF - no top FACE
+      }
+      // init data of side FACEs
+      vector< PrismSide > sides( botEdges.size() );
+      for ( int iS = 0; iS < botEdges.size(); ++iS )
+      {
+        sides[ iS ]._topEdge = botEdges[ iS ]._edge;
+        sides[ iS ]._face    = botF;
+        sides[ iS ]._leftSide  = & sides[ botEdges[ iS ]._iR ];
+        sides[ iS ]._rightSide = & sides[ botEdges[ iS ]._iL ];
+        sides[ iS ]._faces = & facesOfSide[ iS ];
+        sides[ iS ]._faces->Clear();
+      }
+
+      bool isOK = true; // ok for a current botF
+      bool isAdvanced = true;
+      int nbFoundSideFaces = 0;
+      for ( int iLoop = 0; isOK && isAdvanced; ++iLoop )
+      {
+        isAdvanced = false;
+        for ( size_t iS = 0; iS < sides.size() && isOK; ++iS )
+        {
+          PrismSide& side = sides[ iS ];
+          if ( side._face.IsNull() )
+            continue;
+          if ( side._topEdge.IsNull() )
+          {
+            // find vertical EDGEs --- EGDEs 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;
+              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->_faces->Contains( neighborF );
+                if ( isEdgeShared )
+                {
+                  isAdvanced = true;
+                  side._isCheckedEdge[ iE ] = true;
+                  side._nbCheckedEdges++;
+                  int nbNotCheckedE = side._edges->size() - side._nbCheckedEdges;
+                  if ( nbNotCheckedE == 1 )
+                    break;
+                }
+                else
+                {
+                  if ( i == 1 && iLoop == 0 ) isOK = false;
+                  break;
+                }
+              }
+            }
+            // find a top EDGE
+            int nbNotCheckedE = side._edges->size() - side._nbCheckedEdges;
+            if ( nbNotCheckedE == 1 )
+            {
+              vector<bool>::iterator ii = std::find( side._isCheckedEdge.begin(),
+                                                     side._isCheckedEdge.end(), false );
+              if ( ii != side._isCheckedEdge.end() )
+              {
+                size_t iE = std::distance( side._isCheckedEdge.begin(), ii );
+                side._topEdge = side.Edge( iE );
+              }
+            }
+            isOK = ( nbNotCheckedE >= 1 );
+          }
+          else //if ( !side._topEdge.IsNull() )
+          {
+            // get a next face of a side
+            const TopoDS_Shape& f = getAnotherFace( side._face, side._topEdge, facesOfEdge );
+            side._faces->Add( f );
+            bool stop = false;
+            if ( f.IsSame( side._face ) || // _topEdge is a seam
+                 SMESH_MesherHelper::Count( f, TopAbs_WIRE, false ) != 1 )
+            {
+              stop = true;
+            }
+            else if ( side._leftSide != & side ) // not closed side face
+            {
+              if ( side._leftSide->_faces->Contains( f ))
+              {
+                stop = true;
+                side._leftSide->_face.Nullify();
+                side._leftSide->_topEdge.Nullify();
+              }
+              if ( side._rightSide->_faces->Contains( f ))
+              {
+                stop = true;
+                side._rightSide->_face.Nullify();
+                side._rightSide->_topEdge.Nullify();
+              }
+            }
+            if ( stop )
+            {
+              side._face.Nullify();
+              side._topEdge.Nullify();
+              continue;
+            }
+            side._face = TopoDS::Face( f );
+            int faceID = allFaces.FindIndex( side._face );
+            side._edges = & faceEdgesVec[ faceID ];
+            if ( side._edges->empty() )
+              if ( !getEdges( side._face, * side._edges, /*noHoles=*/true ))
+                break;
+            const int nbE = side._edges->size();
+            if ( nbE >= 4 )
+            {
+              isAdvanced = true;
+              ++nbFoundSideFaces;
+              side._iBotEdge = side.FindEdge( side._topEdge );
+              side._isCheckedEdge.clear();
+              side._isCheckedEdge.resize( nbE, false );
+              side._isCheckedEdge[ side._iBotEdge ] = true;
+              side._nbCheckedEdges = 1; // bottom EDGE is known
+            }
+            side._topEdge.Nullify();
+            isOK = ( !side._edges->empty() || side._faces->Extent() > 1 );
+
+          } //if ( !side._topEdge.IsNull() )
+
+        } // loop on prism sides
+
+        if ( nbFoundSideFaces > allFaces.Extent() )
+        {
+          isOK = false;
+        }
+        if ( iLoop > allFaces.Extent() * 10 )
+        {
+          isOK = false;
+#ifdef _DEBUG_
+          cerr << "BUG: infinite loop in StdMeshers_Prism_3D::IsApplicable()" << endl;
+#endif
+        }
+      } // while isAdvanced
+
+      if ( isOK && sides[0]._faces->Extent() > 1 )
+      {
+        const int nbFaces = sides[0]._faces->Extent();
+        if ( botEdges.size() == 1 ) // cylinder
+        {
+          prismDetected = ( nbFaces == allFaces.Extent()-1 );
+        }
+        else
+        {
+          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() );
+        }
+      }
+    } // loop on allFaces
+
+    if ( !prismDetected && toCheckAll ) return false;
+    if ( prismDetected && !toCheckAll ) return true;
+
+  } // loop on solids
+
+  return toCheckAll;
+}
+
 namespace Prism_3D
 {
   //================================================================================
@@ -2352,7 +2775,7 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper*         helper,
     Prism_3D::TQuadList::const_iterator quad = thePrism.myWallQuads[ iE ].begin();
     for ( ; quad != thePrism.myWallQuads[ iE ].end(); ++quad )
     {
-      const TopoDS_Edge& quadBot = (*quad)->side[ QUAD_BOTTOM_SIDE ]->Edge( 0 );
+      const TopoDS_Edge& quadBot = (*quad)->side[ QUAD_BOTTOM_SIDE ].grid->Edge( 0 );
       if ( !myHelper->LoadNodeColumns( faceColumns, (*quad)->face, quadBot, meshDS ))
         return error(COMPERR_BAD_INPUT_MESH, TCom("Can't find regular quadrangle mesh ")
                      << "on a side face #" << MeshDS()->ShapeToIndex( (*quad)->face ));
@@ -2373,7 +2796,7 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper*         helper,
     Prism_3D::TQuadList::const_iterator quad = thePrism.myWallQuads[ iE ].begin();
     for ( ; quad != thePrism.myWallQuads[ iE ].end(); ++quad )
     {
-      const TopoDS_Edge& quadBot = (*quad)->side[ QUAD_BOTTOM_SIDE ]->Edge( 0 );
+      const TopoDS_Edge& quadBot = (*quad)->side[ QUAD_BOTTOM_SIDE ].grid->Edge( 0 );
       if ( !myHelper->LoadNodeColumns( faceColumns, (*quad)->face, quadBot, meshDS ))
         return error(COMPERR_BAD_INPUT_MESH, TCom("Can't find regular quadrangle mesh ")
                      << "on a side face #" << MeshDS()->ShapeToIndex( (*quad)->face ));
@@ -3592,6 +4015,8 @@ TPCurveOnHorFaceAdaptor::TPCurveOnHorFaceAdaptor( const TSideFace*   sideFace,
     const int Z = isTop ? sideFace->ColumnHeight() - 1 : 0;
     map<double, const SMDS_MeshNode* > u2nodes;
     sideFace->GetNodesAtZ( Z, u2nodes );
+    if ( u2nodes.empty() )
+      return;
 
     SMESH_MesherHelper helper( *sideFace->GetMesh() );
     helper.SetSubShape( horFace );
@@ -3656,7 +4081,7 @@ gp_Pnt2d StdMeshers_PrismAsBlock::TPCurveOnHorFaceAdaptor::Value(const Standard_
   map< double, gp_XY >::const_iterator i1 = myUVmap.upper_bound( U );
 
   if ( i1 == myUVmap.end() )
-    return myUVmap.rbegin()->second;
+    return myUVmap.empty() ? gp_XY(0,0) : myUVmap.rbegin()->second;
 
   if ( i1 == myUVmap.begin() )
     return (*i1).second;