Salome HOME
22526: SMESH 2864 - Projection and Extrusion
[modules/smesh.git] / src / StdMeshers / StdMeshers_Prism_3D.cxx
index fbc5704bd593eb2e66cc9112afab729a84c327da..f473b36ba669529e1adf6d24060e7d1138c15df1 100644 (file)
@@ -49,6 +49,7 @@
 #include <Bnd_B3d.hxx>
 #include <Geom2dAdaptor_Curve.hxx>
 #include <Geom2d_Line.hxx>
+#include <GeomLib_IsPlanarSurface.hxx>
 #include <Geom_Curve.hxx>
 #include <TopExp.hxx>
 #include <TopExp_Explorer.hxx>
@@ -661,12 +662,14 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
 
   Prism_3D::TPrismTopo prism;
   myPropagChains = 0;
+  bool selectBottom = meshedFaces.empty();
 
   if ( nbSolids == 1 )
   {
+    TopoDS_Shape solid = TopExp_Explorer( theShape, TopAbs_SOLID ).Current();
     if ( !meshedFaces.empty() )
       prism.myBottom = meshedFaces.front();
-    return ( initPrism( prism, TopExp_Explorer( theShape, TopAbs_SOLID ).Current() ) &&
+    return ( initPrism( prism, solid, selectBottom ) &&
              compute( prism ));
   }
 
@@ -687,6 +690,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
 
   TopTools_MapOfShape meshedSolids;
   list< Prism_3D::TPrismTopo > meshedPrism;
+  list< TopoDS_Face > suspectSourceFaces;
   TopTools_ListIteratorOfListOfShape solidIt;
 
   while ( meshedSolids.Extent() < nbSolids )
@@ -708,7 +712,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
         {
           prism.Clear();
           prism.myBottom = face;
-          if ( !initPrism( prism, solid ) ||
+          if ( !initPrism( prism, solid, selectBottom ) ||
                !compute( prism ))
             return false;
 
@@ -717,6 +721,10 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
           {
             meshedFaces.push_front( prism.myTop );
           }
+          else
+          {
+            suspectSourceFaces.push_back( prism.myTop );
+          }
           meshedPrism.push_back( prism );
         }
       }
@@ -746,6 +754,10 @@ 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
+            }
             // 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);
             PShapeIteratorPtr faceIt = myHelper->GetAncestors( wEdge, *myHelper->GetMesh(),
@@ -753,14 +765,24 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
             while ( const TopoDS_Shape* f = faceIt->next() )
             {
               const TopoDS_Face& candidateF = TopoDS::Face( *f );
+              if ( candidateF.IsSame( wFace )) continue;
+              // select a source FACE: prismIt->myBottom or prismIt->myTop
+              TopoDS_Face sourceF = prismIt->myBottom;
+              for ( TopExp_Explorer v( prismIt->myTop, TopAbs_VERTEX ); v.More(); v.Next() )
+                if ( myHelper->IsSubShape( v.Current(), candidateF )) {
+                  sourceF = prismIt->myTop;
+                  break;
+                }
               prism.Clear();
-              prism.myBottom  = candidateF;
+              prism.myBottom = candidateF;
               mySetErrorToSM = false;
               if ( !myHelper->IsSubShape( candidateF, prismIt->myShape3D ) &&
-                   myHelper->IsSubShape( candidateF, solid ) &&
+                   myHelper ->IsSubShape( candidateF, solid ) &&
                    !myHelper->GetMesh()->GetSubMesh( candidateF )->IsMeshComputed() &&
-                   initPrism( prism, solid ) &&
-                   project2dMesh( prismIt->myBottom, candidateF))
+                   initPrism( prism, solid, /*selectBottom=*/false ) &&
+                   !myHelper->GetMesh()->GetSubMesh( prism.myTop )->IsMeshComputed() &&
+                   !myHelper->GetMesh()->GetSubMesh( prism.myBottom )->IsMeshComputed() &&
+                   project2dMesh( sourceF, prism.myBottom ))
               {
                 mySetErrorToSM = true;
                 if ( !compute( prism ))
@@ -770,6 +792,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
                 {
                   meshedFaces.push_front( prism.myTop );
                   meshedFaces.push_front( prism.myBottom );
+                  selectBottom = false;
                 }
                 meshedPrism.push_back( prism );
                 meshedSolids.Add( solid );
@@ -789,31 +812,52 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
         break; // to compute prisms with avident sources
     }
 
+    if ( meshedFaces.empty() )
+    {
+      meshedFaces.splice( meshedFaces.end(), suspectSourceFaces );
+      selectBottom = true;
+    }
+
     // find FACEs with local 1D hyps, which has to be computed by now,
     // or at least any computed FACEs
-    for ( int iF = 1; ( meshedFaces.empty() && iF < faceToSolids.Extent() ); ++iF )
+    if ( meshedFaces.empty() )
     {
-      const TopoDS_Face&               face = TopoDS::Face( faceToSolids.FindKey( iF ));
-      const TopTools_ListOfShape& solidList = faceToSolids.FindFromKey( face );
-      if ( solidList.IsEmpty() ) continue;
-      SMESH_subMesh*                 faceSM = theMesh.GetSubMesh( face );
-      if ( !faceSM->IsEmpty() )
-      {
-        meshedFaces.push_back( face ); // lower priority
-      }
-      else
+      int prevNbFaces = 0;
+      for ( int iF = 1; iF <= faceToSolids.Extent(); ++iF )
       {
-        bool allSubMeComputed = true;
-        SMESH_subMeshIteratorPtr smIt = faceSM->getDependsOnIterator(false,true);
-        while ( smIt->more() && allSubMeComputed )
-          allSubMeComputed = smIt->next()->IsMeshComputed();
-        if ( allSubMeComputed )
+        const TopoDS_Face&               face = TopoDS::Face( faceToSolids.FindKey( iF ));
+        const TopTools_ListOfShape& solidList = faceToSolids.FindFromKey( face );
+        if ( solidList.IsEmpty() ) continue;
+        SMESH_subMesh*                 faceSM = theMesh.GetSubMesh( face );
+        if ( !faceSM->IsEmpty() )
         {
-          faceSM->ComputeStateEngine( SMESH_subMesh::COMPUTE );
-          if ( !faceSM->IsEmpty() )
-            meshedFaces.push_front( face ); // higher priority
-          else
-            faceSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
+          int nbFaces = faceSM->GetSubMeshDS()->NbElements();
+          if ( prevNbFaces < nbFaces )
+          {
+            if ( !meshedFaces.empty() ) meshedFaces.pop_back();
+            meshedFaces.push_back( face ); // lower priority
+            selectBottom = true;
+            prevNbFaces = nbFaces;
+          }
+        }
+        else
+        {
+          bool allSubMeComputed = true;
+          SMESH_subMeshIteratorPtr smIt = faceSM->getDependsOnIterator(false,true);
+          while ( smIt->more() && allSubMeComputed )
+            allSubMeComputed = smIt->next()->IsMeshComputed();
+          if ( allSubMeComputed )
+          {
+            faceSM->ComputeStateEngine( SMESH_subMesh::COMPUTE );
+            if ( !faceSM->IsEmpty() ) {
+              meshedFaces.push_front( face ); // higher priority
+              selectBottom = true;
+              break;
+            }
+            else {
+              faceSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
+            }
+          }
         }
       }
     }
@@ -839,6 +883,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
           meshedFaces.push_front( prism.myBottom );
           meshedPrism.push_back( prism );
           meshedSolids.Add( solid.Current() );
+          selectBottom = true;
         }
         mySetErrorToSM = true;
       }
@@ -1043,7 +1088,7 @@ bool StdMeshers_Prism_3D::getWallFaces( Prism_3D::TPrismTopo & thePrism,
     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 )));
+      return toSM( error( TCom("Wrong source face#") << shapeID( thePrism.myBottom )));
   }
 
   return true;
@@ -1060,13 +1105,23 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism)
   if ( _computeCanceled )
     return toSM( error( SMESH_ComputeError::New(COMPERR_CANCELED)));
 
+  // Assure the bottom is meshed
+  SMESH_subMesh * botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom );
+  if (( botSM->IsEmpty() ) &&
+      ( ! botSM->GetAlgo() ||
+        ! _gen->Compute( *botSM->GetFather(), botSM->GetSubShape(), /*shapeOnly=*/true )))
+    return error( COMPERR_BAD_INPUT_MESH,
+                  TCom( "No mesher defined to compute the face #")
+                  << shapeID( thePrism.myBottom ));
+
   // Make all side FACEs of thePrism meshed with quads
   if ( !computeWalls( thePrism ))
     return false;
 
   // Analyse mesh and geometry to find all block sub-shapes and submeshes
-  // (after fixing IPAL52499 myBlock is used only as a holder of boundary nodes
-  // and location of internal nodes is computed by StdMeshers_Sweeper)
+  // (after fixing IPAL52499 myBlock is used as a holder of boundary nodes
+  // and for 2D projection in hard cases where StdMeshers_Projection_2D fails;
+  // location of internal nodes is usually computed by StdMeshers_Sweeper)
   if ( !myBlock.Init( myHelper, thePrism ))
     return toSM( error( myBlock.GetError()));
 
@@ -1095,6 +1150,7 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism)
 
   // Projections on the top and bottom faces are taken from nodes existing
   // on these faces; find correspondence between bottom and top nodes
+  myUseBlock = false;
   myBotToColumnMap.clear();
   if ( !assocOrProjBottom2Top( bottomToTopTrsf, thePrism ) ) // it also fills myBotToColumnMap
     return false;
@@ -1104,27 +1160,33 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism)
 
   // use transformation (issue 0020680, IPAL0052499)
   StdMeshers_Sweeper sweeper;
+  double tol;
+  bool allowHighBndError;
 
-  // load boundary nodes
-  bool dummy;
-  list< TopoDS_Edge >::const_iterator edge = thePrism.myBottomEdges.begin();
-  for ( ; edge != thePrism.myBottomEdges.end(); ++edge )
+  if ( !myUseBlock )
   {
-    int edgeID = meshDS->ShapeToIndex( *edge );
-    TParam2ColumnMap* u2col = const_cast<TParam2ColumnMap*>
-      ( myBlock.GetParam2ColumnMap( edgeID, dummy ));
-    TParam2ColumnMap::iterator u2colIt = u2col->begin();
-    for ( ; u2colIt != u2col->end(); ++u2colIt )
-      sweeper.myBndColumns.push_back( & u2colIt->second );
-  }
-  // load node columns inside the bottom face
-  TNode2ColumnMap::iterator bot_column = myBotToColumnMap.begin();
-  for ( ; bot_column != myBotToColumnMap.end(); ++bot_column )
-    sweeper.myIntColumns.push_back( & bot_column->second );
+    // load boundary nodes into sweeper
+    bool dummy;
+    list< TopoDS_Edge >::const_iterator edge = thePrism.myBottomEdges.begin();
+    for ( ; edge != thePrism.myBottomEdges.end(); ++edge )
+    {
+      int edgeID = meshDS->ShapeToIndex( *edge );
+      TParam2ColumnMap* u2col = const_cast<TParam2ColumnMap*>
+        ( myBlock.GetParam2ColumnMap( edgeID, dummy ));
+      TParam2ColumnMap::iterator u2colIt = u2col->begin();
+      for ( ; u2colIt != u2col->end(); ++u2colIt )
+        sweeper.myBndColumns.push_back( & u2colIt->second );
+    }
+    // load node columns inside the bottom face
+    TNode2ColumnMap::iterator bot_column = myBotToColumnMap.begin();
+    for ( ; bot_column != myBotToColumnMap.end(); ++bot_column )
+      sweeper.myIntColumns.push_back( & bot_column->second );
 
-  const double tol = getSweepTolerance( thePrism );
+    tol = getSweepTolerance( thePrism );
+    allowHighBndError = !isSimpleBottom( thePrism );
+  }
 
-  if ( sweeper.ComputeNodes( *myHelper, tol ))
+  if ( !myUseBlock && sweeper.ComputeNodes( *myHelper, tol, allowHighBndError ))
   {
   }
   else // use block approach
@@ -1500,7 +1562,7 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism)
     for ( ; quad != thePrism.myWallQuads[iW].end(); ++quad )
     {
       const TopoDS_Face& face = (*quad)->face;
-      SMESH_subMesh* fSM = mesh->GetSubMesh( face );
+      SMESH_subMesh*      fSM = mesh->GetSubMesh( face );
       if ( ! fSM->IsMeshComputed() )
       {
         // Top EDGEs must be projections from the bottom ones
@@ -1512,6 +1574,8 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism)
         SMESH_subMesh*    topSM = mesh->GetSubMesh( topE );
         SMESH_subMesh*    srcSM = botSM;
         SMESH_subMesh*    tgtSM = topSM;
+        srcSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
+        tgtSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
         if ( !srcSM->IsMeshComputed() && tgtSM->IsMeshComputed() )
           std::swap( srcSM, tgtSM );
 
@@ -1521,7 +1585,6 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism)
           srcSM->ComputeSubMeshStateEngine( SMESH_subMesh::COMPUTE ); // nodes on VERTEXes
           srcSM->ComputeStateEngine( SMESH_subMesh::COMPUTE );        // segments on the EDGE
         }
-        srcSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
 
         if ( tgtSM->IsMeshComputed() &&
              tgtSM->GetSubMeshDS()->NbNodes() != srcSM->GetSubMeshDS()->NbNodes() )
@@ -1909,8 +1972,8 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf
     NSProjUtils::TShapeShapeMap shape2ShapeMap;
     const bool sameTopo =
       NSProjUtils::FindSubShapeAssociation( thePrism.myBottom, myHelper->GetMesh(),
-                                           thePrism.myTop,    myHelper->GetMesh(),
-                                           shape2ShapeMap);
+                                            thePrism.myTop,    myHelper->GetMesh(),
+                                            shape2ShapeMap);
     if ( !sameTopo )
       for ( size_t iQ = 0; iQ < thePrism.myWallQuads.size(); ++iQ )
       {
@@ -1922,10 +1985,10 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf
           for ( int iE = 0; iE < botSide->NbEdges(); ++iE )
           {
             NSProjUtils::InsertAssociation( botSide->Edge( iE ),
-                                           topSide->Edge( iE ), shape2ShapeMap );
+                                            topSide->Edge( iE ), shape2ShapeMap );
             NSProjUtils::InsertAssociation( myHelper->IthVertex( 0, botSide->Edge( iE )),
-                                           myHelper->IthVertex( 0, topSide->Edge( iE )),
-                                           shape2ShapeMap );
+                                            myHelper->IthVertex( 0, topSide->Edge( iE )),
+                                            shape2ShapeMap );
           }
         }
         else
@@ -1940,7 +2003,7 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf
                vt.IsSame( sideT->LastVertex() ))
           {
             NSProjUtils::InsertAssociation( botSide->Edge( 0 ),
-                                           topSide->Edge( 0 ), shape2ShapeMap );
+                                            topSide->Edge( 0 ), shape2ShapeMap );
             NSProjUtils::InsertAssociation( vb, vt, shape2ShapeMap );
           }
           vb = myHelper->IthVertex( 1, botSide->Edge( botSide->NbEdges()-1 ));
@@ -1951,8 +2014,8 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf
                vt.IsSame( sideT->LastVertex() ))
           {
             NSProjUtils::InsertAssociation( botSide->Edge( botSide->NbEdges()-1 ),
-                                           topSide->Edge( topSide->NbEdges()-1 ),
-                                           shape2ShapeMap );
+                                            topSide->Edge( topSide->NbEdges()-1 ),
+                                            shape2ShapeMap );
             NSProjUtils::InsertAssociation( vb, vt, shape2ShapeMap );
           }
         }
@@ -1961,8 +2024,8 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf
     // Find matching nodes of top and bottom faces
     n2nMapPtr = & n2nMap;
     if ( ! NSProjUtils::FindMatchingNodesOnFaces( thePrism.myBottom, myHelper->GetMesh(),
-                                                 thePrism.myTop,    myHelper->GetMesh(),
-                                                 shape2ShapeMap, n2nMap ))
+                                                  thePrism.myTop,    myHelper->GetMesh(),
+                                                  shape2ShapeMap, n2nMap ))
     {
       if ( sameTopo )
         return toSM( error(TCom("Mesh on faces #") << botSM->GetId()
@@ -1985,7 +2048,7 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf
       continue; // wall columns are contained in myBlock
     // create node column
     Prism_3D::TNode bN( botNode );
-    TNode2ColumnMap::iterator bN_col = 
+    TNode2ColumnMap::iterator bN_col =
       myBotToColumnMap.insert( make_pair ( bN, TNodeColumn() )).first;
     TNodeColumn & column = bN_col->second;
     column.resize( zSize );
@@ -2009,6 +2072,11 @@ bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf &             bottom
   {
     return true;
   }
+  NSProjUtils::TNodeNodeMap& n2nMap = 
+    (NSProjUtils::TNodeNodeMap&) TProjction2dAlgo::instance( this )->GetNodesMap();
+  n2nMap.clear();
+
+  myUseBlock = true;
 
   SMESHDS_Mesh*  meshDS = myHelper->GetMeshDS();
   SMESH_subMesh * botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom );
@@ -2018,7 +2086,13 @@ bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf &             bottom
   SMESHDS_SubMesh * topSMDS = topSM->GetSubMeshDS();
 
   if ( topSMDS && topSMDS->NbElements() > 0 )
-    topSM->ComputeStateEngine( SMESH_subMesh::CLEAN );
+  {
+    //topSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); -- avoid propagation of events
+    for ( SMDS_ElemIteratorPtr eIt = topSMDS->GetElements(); eIt->more(); )
+      meshDS->RemoveFreeElement( eIt->next(), topSMDS, /*fromGroups=*/false );
+    for ( SMDS_NodeIteratorPtr nIt = topSMDS->GetNodes(); nIt->more(); )
+      meshDS->RemoveFreeNode( nIt->next(), topSMDS, /*fromGroups=*/false );
+  }
 
   const TopoDS_Face& botFace = thePrism.myBottom; // oriented within
   const TopoDS_Face& topFace = thePrism.myTop;    //    the 3D SHAPE
@@ -2090,6 +2164,8 @@ bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf &             bottom
     column.front() = botNode;
     column.back()  = topNode;
 
+    n2nMap.insert( n2nMap.end(), make_pair( botNode, topNode ));
+
     if ( _computeCanceled )
       return toSM( error( SMESH_ComputeError::New(COMPERR_CANCELED)));
   }
@@ -2139,11 +2215,11 @@ bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf &             bottom
     case 3: {
       newFace = myHelper->AddFace(nodes[0], nodes[1], nodes[2]);
       break;
-      }
+    }
     case 4: {
       newFace = myHelper->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] );
       break;
-      }
+    }
     default:
       newFace = meshDS->AddPolygonalFace( nodes );
     }
@@ -2151,7 +2227,42 @@ bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf &             bottom
       meshDS->SetMeshElementOnShape( newFace, topFaceID );
   }
 
-  myHelper->SetElementsOnShape( oldSetElemsOnShape );  
+  myHelper->SetElementsOnShape( oldSetElemsOnShape );
+
+  // Check the projected mesh
+
+  if ( thePrism.myNbEdgesInWires.size() > 1 && // there are holes
+       topHelper.IsDistorted2D( topSM, /*checkUV=*/false ))
+  {
+    SMESH_MeshEditor editor( topHelper.GetMesh() );
+
+    // smooth in 2D or 3D?
+    TopLoc_Location loc;
+    Handle(Geom_Surface) surface = BRep_Tool::Surface( topFace, loc );
+    bool isPlanar = GeomLib_IsPlanarSurface( surface ).IsPlanar();
+
+    bool isFixed = false;
+    set<const SMDS_MeshNode*> fixedNodes;
+    for ( int iAttemp = 0; !isFixed && iAttemp < 10; ++iAttemp )
+    {
+      TIDSortedElemSet faces;
+      for ( faceIt = topSMDS->GetElements(); faceIt->more(); )
+        faces.insert( faces.end(), faceIt->next() );
+
+      SMESH_MeshEditor::SmoothMethod algo =
+        iAttemp ? SMESH_MeshEditor::CENTROIDAL : SMESH_MeshEditor::LAPLACIAN;
+
+      // smoothing
+      editor.Smooth( faces, fixedNodes, algo, /*nbIterations=*/ 10,
+                     /*theTgtAspectRatio=*/1.0, /*the2D=*/!isPlanar);
+
+      isFixed = !topHelper.IsDistorted2D( topSM, /*checkUV=*/true );
+    }
+    if ( !isFixed )
+      return toSM( error( TCom("Projection from face #") << botSM->GetId()
+                          << " to face #" << topSM->GetId()
+                          << " failed: inverted elements created"));
+  }
 
   return true;
 }
@@ -2227,6 +2338,44 @@ double StdMeshers_Prism_3D::getSweepTolerance( const Prism_3D::TPrismTopo& thePr
   return 0.1 * Sqrt ( minDist );
 }
 
+//=======================================================================
+//function : isSimpleQuad
+//purpose  : check if the bottom FACE is meshable with nice qudrangles,
+//           if so the block aproach can work rather fast.
+//           This is a temporary mean caused by problems in StdMeshers_Sweeper
+//=======================================================================
+
+bool StdMeshers_Prism_3D::isSimpleBottom( const Prism_3D::TPrismTopo& thePrism )
+{
+  // analyse angles between edges
+  double nbConcaveAng = 0, nbConvexAng = 0;
+  TopoDS_Face reverseBottom = TopoDS::Face( thePrism.myBottom.Reversed() ); // see initPrism()
+  TopoDS_Vertex commonV;
+  const list< TopoDS_Edge >& botEdges = thePrism.myBottomEdges;
+  list< TopoDS_Edge >::const_iterator edge = botEdges.begin();
+  for ( ; edge != botEdges.end(); ++edge )
+  {
+    if ( SMESH_Algo::isDegenerated( *edge ))
+      return false;
+    TopoDS_Edge e1 = *edge++;
+    TopoDS_Edge e2 = ( edge == botEdges.end() ? botEdges.front() : *edge );
+    if ( ! TopExp::CommonVertex( e1, e2,  commonV ))
+    {
+      e2 = botEdges.front();
+      if ( ! TopExp::CommonVertex( e1, e2,  commonV ))
+        break;
+    }
+    double angle = myHelper->GetAngle( e1, e2, reverseBottom, commonV );
+    if ( angle < -5 * M_PI/180 )
+      if ( ++nbConcaveAng > 1 )
+        return false;
+    if ( angle > 85 * M_PI/180 )
+      if ( ++nbConvexAng > 4 )
+        return false;
+  }
+  return true;
+}
+
 //=======================================================================
 //function : project2dMesh
 //purpose  : Project mesh faces from a source FACE of one prism (theSrcFace)
@@ -2241,6 +2390,15 @@ bool StdMeshers_Prism_3D::project2dMesh(const TopoDS_Face& theSrcFace,
   bool ok = projector2D->Compute( *myHelper->GetMesh(), theTgtFace );
 
   SMESH_subMesh* tgtSM = myHelper->GetMesh()->GetSubMesh( theTgtFace );
+  if ( !ok && tgtSM->GetSubMeshDS() ) {
+    //tgtSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); -- avoid propagation of events
+    SMESHDS_Mesh*     meshDS = myHelper->GetMeshDS();
+    SMESHDS_SubMesh* tgtSMDS = tgtSM->GetSubMeshDS();
+    for ( SMDS_ElemIteratorPtr eIt = tgtSMDS->GetElements(); eIt->more(); )
+      meshDS->RemoveFreeElement( eIt->next(), tgtSMDS, /*fromGroups=*/false );
+    for ( SMDS_NodeIteratorPtr nIt = tgtSMDS->GetNodes(); nIt->more(); )
+      meshDS->RemoveFreeNode( nIt->next(), tgtSMDS, /*fromGroups=*/false );
+  }
   tgtSM->ComputeStateEngine       ( SMESH_subMesh::CHECK_COMPUTE_STATE );
   tgtSM->ComputeSubMeshStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
 
@@ -2756,16 +2914,18 @@ void StdMeshers_PrismAsBlock::Clear()
 //=======================================================================
 
 bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism,
-                                    const TopoDS_Shape&   shape3D)
+                                    const TopoDS_Shape&   theShape3D,
+                                    const bool            selectBottom)
 {
-  myHelper->SetSubShape( shape3D );
+  myHelper->SetSubShape( theShape3D );
 
-  SMESH_subMesh* mainSubMesh = myHelper->GetMesh()->GetSubMeshContaining( shape3D );
+  SMESH_subMesh* mainSubMesh = myHelper->GetMesh()->GetSubMeshContaining( theShape3D );
   if ( !mainSubMesh ) return toSM( error(COMPERR_BAD_INPUT_MESH,"Null submesh of shape3D"));
 
   // detect not-quad FACE sub-meshes of the 3D SHAPE
   list< SMESH_subMesh* > notQuadGeomSubMesh;
   list< SMESH_subMesh* > notQuadElemSubMesh;
+  list< SMESH_subMesh* > meshedSubMesh;
   int nbFaces = 0;
   //
   SMESH_subMesh* anyFaceSM = 0;
@@ -2787,10 +2947,14 @@ bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism,
     if ( nbWires != 1 || nbEdgesInWires.front() != 4 )
       notQuadGeomSubMesh.push_back( sm );
 
-    // look for not quadrangle mesh elements
-    if ( SMESHDS_SubMesh* smDS = sm->GetSubMeshDS() )
-      if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE ))
+    // look for a not structured sub-mesh
+    if ( !sm->IsEmpty() )
+    {
+      meshedSubMesh.push_back( sm );
+      if ( !myHelper->IsSameElemGeometry( sm->GetSubMeshDS(), SMDSGeom_QUADRANGLE ) ||
+           !myHelper->IsStructured      ( sm ))
         notQuadElemSubMesh.push_back( sm );
+    }
   }
 
   int nbNotQuadMeshed = notQuadElemSubMesh.size();
@@ -2855,33 +3019,50 @@ bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism,
   // use thePrism.myBottom
   if ( !thePrism.myBottom.IsNull() )
   {
-    if ( botSM ) {
+    if ( botSM ) { // <-- not quad geom or mesh on botSM
       if ( ! botSM->GetSubShape().IsSame( thePrism.myBottom )) {
         std::swap( botSM, topSM );
-        if ( !botSM || ! botSM->GetSubShape().IsSame( thePrism.myBottom ))
-          return toSM( error( COMPERR_BAD_INPUT_MESH,
-                              "Incompatible non-structured sub-meshes"));
+        if ( !botSM || ! botSM->GetSubShape().IsSame( thePrism.myBottom )) {
+          if ( !selectBottom )
+            return toSM( error( COMPERR_BAD_INPUT_MESH,
+                                "Incompatible non-structured sub-meshes"));
+          std::swap( botSM, topSM );
+          thePrism.myBottom = TopoDS::Face( botSM->GetSubShape() );
+        }
       }
     }
-    else {
+    else if ( !selectBottom ) {
       botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom );
     }
   }
-  else if ( !botSM ) // find a proper bottom
+  if ( !botSM ) // find a proper bottom
   {
-    // composite walls or not prism shape
-    for ( TopExp_Explorer f( shape3D, TopAbs_FACE ); f.More(); f.Next() )
+    bool savedSetErrorToSM = mySetErrorToSM;
+    mySetErrorToSM = false; // ingore errors in initPrism()
+
+    // search among meshed FACEs
+    list< SMESH_subMesh* >::iterator sm = meshedSubMesh.begin();
+    for ( ; !botSM && sm != meshedSubMesh.end(); ++sm )
+    {
+      thePrism.Clear();
+      botSM             = *sm;
+      thePrism.myBottom = TopoDS::Face( botSM->GetSubShape() );
+      if ( !initPrism( thePrism, theShape3D, /*selectBottom=*/false ))
+        botSM = NULL;
+    }
+    // search among all FACEs
+    for ( TopExp_Explorer f( theShape3D, TopAbs_FACE ); !botSM && f.More(); f.Next() )
     {
       int minNbFaces = 2 + myHelper->Count( f.Current(), TopAbs_EDGE, false);
-      if ( nbFaces >= minNbFaces)
-      {
-        thePrism.Clear();
-        thePrism.myBottom = TopoDS::Face( f.Current() );
-        if ( initPrism( thePrism, shape3D ))
-          return true;
-      }
-      return toSM( error( COMPERR_BAD_SHAPE ));
+      if ( nbFaces < minNbFaces) continue;
+      thePrism.Clear();
+      thePrism.myBottom = TopoDS::Face( f.Current() );
+      botSM             = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom );
+      if ( !initPrism( thePrism, theShape3D, /*selectBottom=*/false ))
+        botSM = NULL;
     }
+    mySetErrorToSM = savedSetErrorToSM;
+    return botSM ? true : toSM( error( COMPERR_BAD_SHAPE ));
   }
 
   // find vertex 000 - the one with smallest coordinates (for easy DEBUG :-)
@@ -2900,11 +3081,11 @@ bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism,
     }
   }
 
-  thePrism.myShape3D = shape3D;
+  thePrism.myShape3D = theShape3D;
   if ( thePrism.myBottom.IsNull() )
     thePrism.myBottom  = TopoDS::Face( botSM->GetSubShape() );
-  thePrism.myBottom.Orientation( myHelper->GetSubShapeOri( shape3D, thePrism.myBottom ));
-  thePrism.myTop.   Orientation( myHelper->GetSubShapeOri( shape3D, thePrism.myTop ));
+  thePrism.myBottom.Orientation( myHelper->GetSubShapeOri( theShape3D, thePrism.myBottom ));
+  thePrism.myTop.   Orientation( myHelper->GetSubShapeOri( theShape3D, thePrism.myTop ));
 
   // Get ordered bottom edges
   TopoDS_Face reverseBottom = // to have order of top EDGEs as in the top FACE
@@ -2914,7 +3095,7 @@ bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism,
                                 thePrism.myNbEdgesInWires, V000 );
 
   // Get Wall faces corresponding to the ordered bottom edges and the top FACE
-  if ( !getWallFaces( thePrism, nbFaces ))
+  if ( !getWallFaces( thePrism, nbFaces )) // it also sets thePrism.myTop
     return false; //toSM( error(COMPERR_BAD_SHAPE, "Can't find side faces"));
 
   if ( topSM )
@@ -3858,7 +4039,7 @@ gp_Pnt StdMeshers_PrismAsBlock::TSideFace::Value(const Standard_Real U,
       TopoDS_Shape s = myHelper.GetSubShapeByNode( nn[0], myHelper.GetMeshDS() );
       if ( s.ShapeType() != TopAbs_EDGE )
         s = myHelper.GetSubShapeByNode( nn[2], myHelper.GetMeshDS() );
-      if ( s.ShapeType() == TopAbs_EDGE )
+      if ( !s.IsNull() && s.ShapeType() == TopAbs_EDGE )
         edge = TopoDS::Edge( s );
     }
     if ( !edge.IsNull() )
@@ -4401,7 +4582,8 @@ void StdMeshers_Sweeper::applyBoundaryError(const vector< gp_XYZ >& bndPoints,
 //================================================================================
 
 bool StdMeshers_Sweeper::ComputeNodes( SMESH_MesherHelper& helper,
-                                       const double        tol)
+                                       const double        tol,
+                                       const bool          allowHighBndError)
 {
   const size_t zSize = myBndColumns[0]->size();
   const size_t zSrc = 0, zTgt = zSize-1;
@@ -4520,6 +4702,9 @@ bool StdMeshers_Sweeper::ComputeNodes( SMESH_MesherHelper& helper,
     bndErrorIsSmall = ( sumError < tol );
   }
 
+  if ( !bndErrorIsSmall && !allowHighBndError )
+    return false;
+
   // compute final points on the central layer
   std::vector< double > int2BndDist( myBndColumns.size() ); // work array of applyBoundaryError()
   double r = zS / ( zSize - 1.);