Salome HOME
Fatal error if F2C converter is not found. master
authorrnv <rnv@opencascade.com>
Fri, 27 Nov 2020 12:56:27 +0000 (15:56 +0300)
committerrnv <rnv@opencascade.com>
Fri, 27 Nov 2020 12:56:27 +0000 (15:56 +0300)
23 files changed:
CMakeLists.txt
doc/salome/gui/SMESH/input/cartesian_algo.rst
doc/salome/gui/SMESH/input/define_mesh_by_script.rst
src/SMESH/SMESH_Algo.cxx
src/SMESH/SMESH_Gen.cxx
src/SMESH/SMESH_Gen.hxx
src/SMESH/SMESH_HypoFilter.cxx
src/SMESH/SMESH_MeshEditor.cxx
src/SMESH/SMESH_subMesh.cxx
src/SMESH/SMESH_subMesh.hxx
src/SMESHGUI/SMESHGUI_Displayer.cxx
src/SMESHGUI/SMESHGUI_Displayer.h
src/SMESHGUI/SMESHGUI_MeshOrderOp.cxx
src/SMESHGUI/SMESHGUI_VTKUtils.cxx
src/SMESHGUI/SMESHGUI_VTKUtils.h
src/SMESH_I/SMESH_Gen_i_1.cxx
src/SMESH_I/SMESH_MeshEditor_i.cxx
src/SMESH_I/SMESH_Mesh_i.cxx
src/SMESH_SWIG/StdMeshersBuilder.py
src/SMESH_SWIG/smeshBuilder.py
src/StdMeshers/StdMeshers_Import_1D.cxx
src/StdMeshers/StdMeshers_Prism_3D.cxx
src/StdMeshers/StdMeshers_Prism_3D.hxx

index 6e6839a..6796fcf 100644 (file)
@@ -27,7 +27,7 @@ INCLUDE(CMakeDependentOption)
 STRING(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UC)
 
 SET(${PROJECT_NAME_UC}_MAJOR_VERSION 9)
-SET(${PROJECT_NAME_UC}_MINOR_VERSION 5)
+SET(${PROJECT_NAME_UC}_MINOR_VERSION 6)
 SET(${PROJECT_NAME_UC}_PATCH_VERSION 0)
 SET(${PROJECT_NAME_UC}_VERSION
   ${${PROJECT_NAME_UC}_MAJOR_VERSION}.${${PROJECT_NAME_UC}_MINOR_VERSION}.${${PROJECT_NAME_UC}_PATCH_VERSION})
@@ -223,7 +223,7 @@ IF(WIN32)
     SET(SALOME_SMESH_ENABLE_MEFISTO ON)
     MESSAGE(STATUS "Build MEFISTO2D mesher using Fortran to C generator")
   ELSE(${F2C_FOUND})
-    MESSAGE(STATUS "Fortran to C generator is not found: MEFISTO2D mesher will be unavailable.")
+    MESSAGE(FATAL "Fortran to C generator is not found: MEFISTO2D mesher cannot be compiled! Please define F2C_ROOT_DIR !")
   ENDIF(${F2C_FOUND})  
 ENDIF(WIN32)
 
index 3458728..76b150e 100644 (file)
@@ -59,6 +59,8 @@ This dialog allows to define
     
        * You can specify the **Coordinates** of grid nodes. **Insert** button inserts a node at **Step** distance (negative or positive) from the selected node. **Delete** button removes the selected node. Double click on a coordinate in the list enables its edition. **Note** that node coordinates are measured along directions of axes that can differ from the directions of the Global Coordinate System.
        * You can define the **Spacing** of a grid as an algebraic formula *f(t)* where *t* is a position along a grid axis normalized at [0.0,1.0]. *f(t)* must be non-negative at 0. <= *t* <= 1. The whole extent of geometry can be divided into ranges with their own spacing formulas to apply; a t varies between 0.0 and 1.0 within each **Range**. **Insert** button divides a selected range into two. **Delete** button adds the selected sub-range to the previous one. Double click on a range in the list enables edition of its right boundary. Double click on a function in the list enables its edition.
+
+.. note:: The actual grid spacing can slightly differ from the defined one. This is done for the best fitting of polyhedrons and for a better mesh quality on the interval boundaries. For example, if a constant **Spacing** is defined along an axis, the actual grid will fill the shape's dimension L along this axis with round number of equal cells: Spacing_actual = L / round( L / Spacing_defined ).
   
 * **Fixed Point** group allows defining an exact location of a grid node in the direction defined by spacing. The following cases are possible:
    
index 9238777..43d7f89 100644 (file)
@@ -15,7 +15,9 @@ meshes and to create 2D mesh by your python code. For this, you
 #. run your python code, which creates a 2D mesh,
 #. invoke **Compute** command, which computes a 3D mesh.
 
-.. warning:: **Use Edges to be Created Manually** and **Use Faces to be Created Manually** algorithms should be assigned *before* mesh generation by the Python code.
+  .. warning::
+     * **Use Edges to be Created Manually** and **Use Faces to be Created Manually** algorithms should be assigned *before* mesh generation by the Python code.
+     * Nodes and elements created in your script must be assigned to geometry entities by calling *SetMeshElementOnShape*, *SetNodeOnVertex*, *SetNodeOnEdge* etc. in order to be used by an algorithm of upper dimension.
 
 Consider trying a sample script demonstrating the usage of :ref:`Use Faces to be Created Manually <tui_use_existing_faces>` algorithm for construction of a 2D mesh using Python commands.
 
index d493081..bdc93b1 100644 (file)
@@ -950,10 +950,9 @@ void SMESH_Algo::InitComputeError()
 {
   _error = COMPERR_OK;
   _comment.clear();
-  list<const SMDS_MeshElement*>::iterator elem = _badInputElements.begin();
-  for ( ; elem != _badInputElements.end(); ++elem )
-    if ( (*elem)->GetID() < 1 )
-      delete *elem;
+  for ( const SMDS_MeshElement* & elem : _badInputElements )
+    if ( !elem->IsNull() && elem->GetID() < 1 )
+      delete elem;
   _badInputElements.clear();
   _mesh = 0;
 
@@ -1015,6 +1014,7 @@ void SMESH_Algo::addBadInputElements(const SMESHDS_SubMesh* sm,
       SMDS_ElemIteratorPtr eIt = sm->GetElements();
       while ( eIt->more() ) addBadInputElement( eIt->next() );
     }
+    _mesh = sm->GetParent();
   }
 }
 
index f00d3a4..6635311 100644 (file)
@@ -63,6 +63,43 @@ using namespace std;
   #define env_sep ':'
 #endif
 
+namespace
+{
+  // a structure used to nullify SMESH_Gen field of SMESH_Hypothesis,
+  // which is needed for SMESH_Hypothesis not deleted before ~SMESH_Gen()
+  struct _Hyp : public SMESH_Hypothesis
+  {
+    void NullifyGen()
+    {
+      _gen = 0;
+    }
+  };
+
+  //================================================================================
+  /*!
+   * \brief Fill a map of shapes with all sub-shape of a sub-mesh
+   */
+  //================================================================================
+
+  TopTools_IndexedMapOfShape * fillAllowed( SMESH_subMesh*               sm,
+                                            const bool                   toFill,
+                                            TopTools_IndexedMapOfShape * allowedSub )
+  {
+    if ( !toFill || !allowedSub )
+    {
+      return nullptr;
+    }
+    if ( allowedSub->IsEmpty() )
+    {
+      allowedSub->ReSize( sm->DependsOn().size() + 1 );
+      allowedSub->Add( sm->GetSubShape() );
+      for ( const auto & key_sm : sm->DependsOn() )
+        allowedSub->Add( key_sm.second->GetSubShape() );
+    }
+    return allowedSub;
+  }
+}
+
 //=============================================================================
 /*!
  *  Constructor
@@ -79,19 +116,6 @@ SMESH_Gen::SMESH_Gen()
   _compute_canceled = false;
 }
 
-namespace
-{
-  // a structure used to nullify SMESH_Gen field of SMESH_Hypothesis,
-  // which is needed for SMESH_Hypothesis not deleted before ~SMESH_Gen()
-  struct _Hyp : public SMESH_Hypothesis
-  {
-    void NullifyGen()
-    {
-      _gen = 0;
-    }
-  };
-}
-
 //=============================================================================
 /*!
  * Destructor
@@ -138,11 +162,12 @@ SMESH_Mesh* SMESH_Gen::CreateMesh(bool theIsEmbeddedMode)
  */
 //=============================================================================
 
-bool SMESH_Gen::Compute(SMESH_Mesh &          aMesh,
-                        const TopoDS_Shape &  aShape,
-                        const int             aFlags /*= COMPACT_MESH*/,
-                        const ::MeshDimension aDim /*=::MeshDim_3D*/,
-                        TSetOfInt*            aShapesId /*=0*/)
+bool SMESH_Gen::Compute(SMESH_Mesh &                aMesh,
+                        const TopoDS_Shape &        aShape,
+                        const int                   aFlags /*= COMPACT_MESH*/,
+                        const ::MeshDimension       aDim /*=::MeshDim_3D*/,
+                        TSetOfInt*                  aShapesId /*=0*/,
+                        TopTools_IndexedMapOfShape* anAllowedSubShapes/*=0*/)
 {
   MEMOSTAT;
 
@@ -152,7 +177,7 @@ bool SMESH_Gen::Compute(SMESH_Mesh &          aMesh,
 
   bool ret = true;
 
-  SMESH_subMesh *sm = aMesh.GetSubMesh(aShape);
+  SMESH_subMesh *sm, *shapeSM = aMesh.GetSubMesh(aShape);
 
   const bool includeSelf = true;
   const bool complexShapeFirst = true;
@@ -168,13 +193,17 @@ bool SMESH_Gen::Compute(SMESH_Mesh &          aMesh,
   if ( !aMesh.HasShapeToMesh() )
     computeEvent = SMESH_subMesh::COMPUTE_NOGEOM; // if several algos and no geometry
 
+  TopTools_IndexedMapOfShape *allowedSubShapes = anAllowedSubShapes, allowedSub;
+  if ( aShapeOnly && !allowedSubShapes )
+    allowedSubShapes = &allowedSub;
+
   if ( anUpward ) // is called from the below code in this method
   {
     // ===============================================
     // Mesh all the sub-shapes starting from vertices
     // ===============================================
 
-    smIt = sm->getDependsOnIterator(includeSelf, !complexShapeFirst);
+    smIt = shapeSM->getDependsOnIterator(includeSelf, !complexShapeFirst);
     while ( smIt->more() )
     {
       SMESH_subMesh* smToCompute = smIt->next();
@@ -198,9 +227,11 @@ bool SMESH_Gen::Compute(SMESH_Mesh &          aMesh,
       {
         if (_compute_canceled)
           return false;
+        smToCompute->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes ));
         setCurrentSubMesh( smToCompute );
         smToCompute->ComputeStateEngine( computeEvent );
-        setCurrentSubMesh( NULL );
+        setCurrentSubMesh( nullptr );
+        smToCompute->SetAllowedSubShapes( nullptr );
       }
 
       // we check all the sub-meshes here and detect if any of them failed to compute
@@ -233,7 +264,7 @@ bool SMESH_Gen::Compute(SMESH_Mesh &          aMesh,
     TopoDS_Shape algoShape;
     int prevShapeDim = -1, aShapeDim;
 
-    smIt = sm->getDependsOnIterator(includeSelf, complexShapeFirst);
+    smIt = shapeSM->getDependsOnIterator(includeSelf, complexShapeFirst);
     while ( smIt->more() )
     {
       SMESH_subMesh* smToCompute = smIt->next();
@@ -285,9 +316,11 @@ bool SMESH_Gen::Compute(SMESH_Mesh &          aMesh,
         {
           if (_compute_canceled)
             return false;
+          smToCompute->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes ));
           setCurrentSubMesh( smToCompute );
           smToCompute->ComputeStateEngine( computeEvent );
-          setCurrentSubMesh( NULL );
+          setCurrentSubMesh( nullptr );
+          smToCompute->SetAllowedSubShapes( nullptr );
           if ( aShapesId )
             aShapesId->insert( smToCompute->GetId() );
         }
@@ -335,7 +368,6 @@ bool SMESH_Gen::Compute(SMESH_Mesh &          aMesh,
 
           const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
           const int aShapeDim = GetShapeDim( aSubShape );
-          //if ( aSubShape.ShapeType() == TopAbs_VERTEX ) continue;
           if ( aShapeDim < 1 ) continue;
 
           // check for preview dimension limitations
@@ -350,11 +382,14 @@ bool SMESH_Gen::Compute(SMESH_Mesh &          aMesh,
           if ( SMESH_Algo* subAlgo = (SMESH_Algo*) aMesh.GetHypothesis( smToCompute, filter, true))
           {
             if ( ! subAlgo->NeedDiscreteBoundary() ) continue;
+            TopTools_IndexedMapOfShape* localAllowed = allowedSubShapes;
+            if ( localAllowed && localAllowed->IsEmpty() )
+              localAllowed = 0; // prevent fillAllowed() with  aSubShape
+
             SMESH_Hypothesis::Hypothesis_Status status;
             if ( subAlgo->CheckHypothesis( aMesh, aSubShape, status ))
               // mesh a lower smToCompute starting from vertices
-              Compute( aMesh, aSubShape, aFlags | SHAPE_ONLY_UPWARD, aDim, aShapesId );
-              // Compute( aMesh, aSubShape, aShapeOnly, /*anUpward=*/true, aDim, aShapesId );
+              Compute( aMesh, aSubShape, aFlags | SHAPE_ONLY_UPWARD, aDim, aShapesId, localAllowed );
           }
         }
       }
@@ -373,9 +408,11 @@ bool SMESH_Gen::Compute(SMESH_Mesh &          aMesh,
 
           if (_compute_canceled)
             return false;
+          sm->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes ));
           setCurrentSubMesh( sm );
           sm->ComputeStateEngine( computeEvent );
           setCurrentSubMesh( NULL );
+          sm->SetAllowedSubShapes( nullptr );
           if ( aShapesId )
             aShapesId->insert( sm->GetId() );
         }
@@ -385,7 +422,7 @@ bool SMESH_Gen::Compute(SMESH_Mesh &          aMesh,
     // -----------------------------------------------
     // mesh the rest sub-shapes starting from vertices
     // -----------------------------------------------
-    ret = Compute( aMesh, aShape, aFlags | UPWARD, aDim, aShapesId );
+    ret = Compute( aMesh, aShape, aFlags | UPWARD, aDim, aShapesId, allowedSubShapes );
   }
 
   MEMOSTAT;
@@ -399,7 +436,7 @@ bool SMESH_Gen::Compute(SMESH_Mesh &          aMesh,
     SMESH_MesherHelper aHelper( aMesh );
     if ( aHelper.IsQuadraticMesh() != SMESH_MesherHelper::LINEAR )
     {
-      aHelper.FixQuadraticElements( sm->GetComputeError() );
+      aHelper.FixQuadraticElements( shapeSM->GetComputeError() );
     }
   }
 
index c94693a..e73fe61 100644 (file)
@@ -42,6 +42,7 @@
 #include <string>
 
 #include <TopoDS_Shape.hxx>
+#include <TopTools_IndexedMapOfShape.hxx>
 
 class SMESHDS_Document;
 class SMESH_Algo;
@@ -83,13 +84,15 @@ public:
    *  \param aFlags - ComputeFlags. By default compute the whole mesh and compact at the end.
    *  \param aDim - upper level dimension of the mesh computation (for preview)
    *  \param aShapesId - list of shapes with computed mesh entities (elements or nodes)
+   *  \param anAllowedSubShapes - shapes to mesh only. Mesh all if empty or nullptr
    *  \retval bool - true if none sub-mesh failed to compute
    */
-  bool Compute(::SMESH_Mesh &        aMesh,
-               const TopoDS_Shape &  aShape,
-               const int             aFlags = COMPACT_MESH,
-               const ::MeshDimension aDim=::MeshDim_3D,
-               TSetOfInt*            aShapesId=0);
+  bool Compute(::SMESH_Mesh &              aMesh,
+               const TopoDS_Shape &        aShape,
+               const int                   aFlags = COMPACT_MESH,
+               const ::MeshDimension       aDim=::MeshDim_3D,
+               TSetOfInt*                  aShapesId=0,
+               TopTools_IndexedMapOfShape* anAllowedSubShapes=0);
 
   void PrepareCompute(::SMESH_Mesh &        aMesh,
                       const TopoDS_Shape &  aShape);
index e1100ac..ecbd64b 100644 (file)
@@ -156,7 +156,7 @@ void SMESH_HypoFilter::IsMoreLocalThanPredicate::findPreferable()
 
 //=======================================================================
 //function : IsMoreLocalThanPredicate::IsOk
-//purpose  : 
+//purpose  : Check if aShape is more local than this->_shape
 //=======================================================================
 
 bool SMESH_HypoFilter::IsMoreLocalThanPredicate::IsOk(const SMESH_Hypothesis* aHyp,
@@ -169,16 +169,23 @@ bool SMESH_HypoFilter::IsMoreLocalThanPredicate::IsOk(const SMESH_Hypothesis* aH
   if ( SMESH_MesherHelper::IsSubShape( aShape, /*mainShape=*/_shape ))
     return true;
 
-  if ( aShape.ShapeType() == TopAbs_COMPOUND && 
+  if ( aShape.ShapeType() == TopAbs_COMPOUND &&
        !SMESH_MesherHelper::IsSubShape( _shape, /*mainShape=*/aShape)) // issue 0020963
   {
-    for ( int type = TopAbs_SOLID; type < TopAbs_SHAPE; ++type )
-      if ( aHyp->GetDim() == SMESH_Gen::GetShapeDim( TopAbs_ShapeEnum( type )))
-        for ( TopExp_Explorer exp( aShape, TopAbs_ShapeEnum( type )); exp.More(); exp.Next())
-          if ( SMESH_MesherHelper::IsSubShape( exp.Current(), /*mainShape=*/_shape ))
-            return true;
+    // [bos#22320] compound of FACEs is MORE local than compound of SOLIDs
+    TopAbs_ShapeEnum givenType = SMESH_MesherHelper::GetGroupType( _shape );
+    TopAbs_ShapeEnum   hypType = SMESH_MesherHelper::GetGroupType( aShape );
+    if ( SMESH_Gen::GetShapeDim( givenType ) > SMESH_Gen::GetShapeDim( hypType ))
+    {
+      for ( int type = TopAbs_SOLID; type < TopAbs_SHAPE; ++type )
+        if ( aHyp->GetDim() == SMESH_Gen::GetShapeDim( TopAbs_ShapeEnum( type )))
+          for ( TopExp_Explorer exp( aShape, TopAbs_ShapeEnum( type )); exp.More(); exp.Next())
+            if ( SMESH_MesherHelper::IsSubShape( exp.Current(), /*mainShape=*/_shape ))
+              return true;
+    }
   }
 
+  // take forced sub-mesh priority into account
   if ( _preferableShapes.Contains( aShape ))
     return true; // issue 21559, Mesh_6
 
@@ -187,7 +194,7 @@ bool SMESH_HypoFilter::IsMoreLocalThanPredicate::IsOk(const SMESH_Hypothesis* aH
 
 //=======================================================================
 //function : SMESH_HypoFilter
-//purpose  : 
+//purpose  :
 //=======================================================================
 
 SMESH_HypoFilter::SMESH_HypoFilter()
index ae3b703..1d679c2 100644 (file)
@@ -1504,9 +1504,12 @@ void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
   SMESH_MesherHelper helper( *GetMesh() );
   helper.SetElementsOnShape( true );
 
-  SMDS_ElemIteratorPtr faceIt;
-  if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face);
-  else                    faceIt = SMESHUtils::elemSetIterator( theElems );
+  // get standalone groups of faces
+  vector< SMDS_MeshGroup* > allFaceGroups, faceGroups;
+  for ( SMESHDS_GroupBase* grBase : GetMeshDS()->GetGroups() )
+    if ( SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( grBase ))
+      if ( group->GetType() == SMDSAbs_Face && !group->IsEmpty() )
+        allFaceGroups.push_back( & group->SMDSGroup() );
 
   bool   checkUV;
   gp_XY  uv [9]; uv[8] = gp_XY(0,0);
@@ -1517,6 +1520,10 @@ void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
   Handle(Geom_Surface)           surface;
   TopLoc_Location                loc;
 
+  SMDS_ElemIteratorPtr faceIt;
+  if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face);
+  else                    faceIt = SMESHUtils::elemSetIterator( theElems );
+
   while ( faceIt->more() )
   {
     const SMDS_MeshElement* quad = faceIt->next();
@@ -1593,13 +1600,19 @@ void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
       myLastCreatedNodes.push_back( nCentral );
     }
 
-    // create 4 triangles
-
     helper.SetIsQuadratic  ( nodes.size() > 4 );
     helper.SetIsBiQuadratic( nodes.size() == 9 );
     if ( helper.GetIsQuadratic() )
       helper.AddTLinks( static_cast< const SMDS_MeshFace*>( quad ));
 
+    // select groups to update
+    faceGroups.clear();
+    for ( SMDS_MeshGroup* group : allFaceGroups )
+      if ( group->Remove( quad ))
+        faceGroups.push_back( group );
+
+    // create 4 triangles
+
     GetMeshDS()->RemoveFreeElement( quad, subMeshDS, /*fromGroups=*/false );
 
     for ( int i = 0; i < 4; ++i )
@@ -1607,8 +1620,9 @@ void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
       SMDS_MeshElement* tria = helper.AddFace( nodes[ i ],
                                                nodes[(i+1)%4],
                                                nCentral );
-      ReplaceElemInGroups( tria, quad, GetMeshDS() );
       myLastCreatedElems.push_back( tria );
+      for ( SMDS_MeshGroup* group : faceGroups )
+        group->Add( tria );
     }
   }
 }
index 63344a5..4f9955c 100644 (file)
@@ -110,6 +110,7 @@ SMESH_subMesh::SMESH_subMesh(int                  Id,
   }
   _computeCost = 0; // how costly is to compute this sub-mesh
   _realComputeCost = 0;
+  _allowedSubShapes = nullptr;
 }
 
 //=============================================================================
@@ -271,6 +272,42 @@ bool SMESH_subMesh::IsMeshComputed() const
   return false;
 }
 
+//================================================================================
+/*!
+ * \brief Check if any upper level sub-shape is not computed.
+ *        Used to update a sub-mesh icon
+ */
+//================================================================================
+
+bool SMESH_subMesh::IsComputedPartially() const
+{
+  SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(/*includeSelf=*/true,
+                                                       /*SolidFirst=*/true);
+  bool allComputed = true;
+  TopAbs_ShapeEnum readyType = TopAbs_VERTEX; // max value
+  while ( smIt->more() && allComputed )
+  {
+    SMESH_subMesh* sm = smIt->next();
+
+    if ( sm->GetSubShape().ShapeType() > readyType )
+      break; // lower dimension -> stop
+    if ( sm->GetComputeState() != SMESH_subMesh::NOT_READY )
+      readyType = sm->GetSubShape().ShapeType();
+
+    switch ( sm->GetComputeState() )
+    {
+    case SMESH_subMesh::READY_TO_COMPUTE:
+    case SMESH_subMesh::FAILED_TO_COMPUTE:
+      allComputed = false;// sm->IsMeshComputed();
+      break;
+    case SMESH_subMesh::NOT_READY:
+    case SMESH_subMesh::COMPUTE_OK:
+      continue;
+    }
+  }
+  return !allComputed;
+}
+
 //=============================================================================
 /*!
  * Return true if all sub-meshes have been meshed
@@ -1478,11 +1515,14 @@ bool SMESH_subMesh::ComputeStateEngine(compute_event event)
         if (_father->HasShapeToMesh() ) {
           bool subComputed = false, subFailed = false;
           if (!algo->OnlyUnaryInput()) {
-            if ( event == COMPUTE /*&&
-                 ( algo->NeedDiscreteBoundary() || algo->SupportSubmeshes() )*/)
-              shape = getCollection( gen, algo, subComputed, subFailed, algo->SubMeshesToCompute());
-            else
-              subComputed = SubMeshesComputed( & subFailed );
+            //  --- commented for bos#22320 to compute all sub-shapes at once if possible;
+            //  --- in case COMPUTE_SUBMESH, set of sub-shapes is limited
+            //  --- by calling SetAllowedSubShapes()
+            // if ( event == COMPUTE )
+            //   shape = getCollection( gen, algo, subComputed, subFailed, algo->SubMeshesToComput;
+            // else
+            //   subComputed = SubMeshesComputed( & subFailed );
+            shape = getCollection( gen, algo, subComputed, subFailed, algo->SubMeshesToCompute());
           }
           else {
             subComputed = SubMeshesComputed();
@@ -1610,8 +1650,9 @@ bool SMESH_subMesh::ComputeStateEngine(compute_event event)
             ((SMESHDS_Hypothesis*)hyps.front())->SaveTo( hypStr.Stream() );
             hypStr << " ";
           }
-          cout << _algo->GetName()
-               << " " << _father->GetSubMesh( subS.Current() )->GetId()
+          cout << _father->GetSubMesh( subS.Current() )->GetId()
+               << " " << ( ret ? "OK" : "FAIL" )
+               << " " << _algo->GetName()
                << " " << hypStr << endl;
         }
 #endif
@@ -1747,6 +1788,8 @@ bool SMESH_subMesh::ComputeStateEngine(compute_event event)
       break;
     case COMPUTE:               // nothing to do
       break;
+    case COMPUTE_SUBMESH:       // nothing to do
+      break;
     case COMPUTE_CANCELED:      // nothing to do
       break;
     case CLEAN:
@@ -2140,6 +2183,8 @@ TopoDS_Shape SMESH_subMesh::getCollection(SMESH_Gen * theGen,
     const TopoDS_Shape&  S = subMesh->_subShape;
     if ( S.ShapeType() != this->_subShape.ShapeType() )
       continue;
+    if ( _allowedSubShapes && !_allowedSubShapes->IsEmpty() && !_allowedSubShapes->Contains( S ))
+      continue;
     if ( subMesh == this )
     {
       aBuilder.Add( aCompound, S );
index 03dd98e..a2eef50 100644 (file)
@@ -36,6 +36,7 @@
 #include "Utils_SALOME_Exception.hxx"
 
 #include <TopoDS_Shape.hxx>
+#include <TopTools_IndexedMapOfShape.hxx>
 
 #include <list>
 #include <map>
@@ -256,6 +257,15 @@ public:
   bool IsMeshComputed() const;
   // check if _subMeshDS contains mesh elements unless _alwaysComputed==true
 
+  bool IsComputedPartially() const;
+  // check if any upper level sub-shape is not computed
+
+  /*!
+   * \brief Set sub-shapes that are allowed to compute at once by a multidimensional algo
+   */
+  void SetAllowedSubShapes( const TopTools_IndexedMapOfShape* subShapes )
+  { _allowedSubShapes = subShapes; }
+
   /*!
    * \brief Allow algo->Compute() if a subshape of lower dim is meshed but
    *        none mesh entity is bound to it
@@ -344,6 +354,8 @@ protected:
   // mesh several edges as a whole and leave some of them  without mesh entities
   bool                  _alwaysComputed;
 
+  const TopTools_IndexedMapOfShape* _allowedSubShapes; // allowed to be returned by getCollection()
+
 };
 
 #endif
index adeb2d7..53bb6c4 100644 (file)
@@ -46,7 +46,8 @@
 
 SMESHGUI_Displayer::SMESHGUI_Displayer( SalomeApp_Application* app )
 : LightApp_Displayer(),
-  myApp( app )
+  myApp( app ),
+  isNeedFitAll(false)
 {
 }
 
@@ -71,6 +72,7 @@ SALOME_Prs* SMESHGUI_Displayer::buildPresentation( const QString& entry, SALOME_
         anActor = SMESH::CreateActor( entry.toUtf8().data(), true );
       if( anActor )
       {
+        isNeedFitAll = SMESH::NoSmeshActors();
         SMESH::DisplayActor( wnd, anActor );
         prs = LightApp_Displayer::buildPresentation( entry.toUtf8().data(), aViewFrame );
       }
@@ -113,3 +115,13 @@ bool SMESHGUI_Displayer::canBeDisplayed( const QString& entry, const QString& vi
   }
   return res;
 }
+
+void SMESHGUI_Displayer::Display( const QStringList& theList, const bool anUpdateViewer, SALOME_View* theView ) 
+{
+  LightApp_Displayer::Display( theList, anUpdateViewer, theView );
+  
+  if (isNeedFitAll) {
+    SMESH::FitAll();
+    isNeedFitAll = false;
+  }
+}
\ No newline at end of file
index 6a1fce5..3777cfc 100644 (file)
@@ -42,14 +42,16 @@ public:
   SMESHGUI_Displayer( SalomeApp_Application* );
   ~SMESHGUI_Displayer();
 
-  virtual SALOME_Prs*      buildPresentation( const QString&, SALOME_View* = 0 );
-  virtual bool             canBeDisplayed( const QString&, const QString& ) const;
+  virtual SALOME_Prs*      buildPresentation( const QString&, SALOME_View* = 0 ) override;
+  virtual bool             canBeDisplayed( const QString&, const QString& ) const override;
+  virtual void             Display( const QStringList&, const bool = true, SALOME_View* = 0) override;
 
 protected:
   SalomeApp_Study*         study() const;
 
 private:
   SalomeApp_Application*   myApp;
+  bool                     isNeedFitAll;
 };
 
 #endif // SMESHGUI_DISPLAYER_H
index 2c17777..4f459d4 100644 (file)
@@ -53,7 +53,7 @@ SMESHGUI_MeshOrderOp::SMESHGUI_MeshOrderOp()
 {
   myDlg = new SMESHGUI_MeshOrderDlg( desktop() );
   
-  myHelpFileName = "constructing_meshes.html#mesh-order-anchor";
+  myHelpFileName = "constructing_meshes.html#submesh-order-anchor";
 }
 
 //================================================================================
index b148eff..f1ca735 100644 (file)
@@ -726,9 +726,10 @@ namespace SMESH
    */
   //================================================================================
 
-  bool noSmeshActors(SUIT_ViewWindow *theWnd)
+  bool NoSmeshActors(SUIT_ViewWindow *theWnd)
   {
-    if(SVTK_ViewWindow* aViewWindow = GetVtkViewWindow(theWnd)) {
+    SUIT_ViewWindow* aWnd = ( theWnd == nullptr ) ? GetActiveWindow() : theWnd;
+    if(SVTK_ViewWindow* aViewWindow = GetVtkViewWindow(aWnd)) {
       vtkRenderer *aRenderer = aViewWindow->getRenderer();
       VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
       vtkActorCollection *aCollection = aCopy.GetActors();
@@ -826,7 +827,7 @@ namespace SMESH
               if ( (aVisualObj = GetVisualObj(theEntry)) && aVisualObj->IsValid())
               {
                 if ((anActor = CreateActor(theEntry,true))) {
-                  bool needFitAll = noSmeshActors(theWnd); // fit for the first object only
+                  bool needFitAll = NoSmeshActors(theWnd); // fit for the first object only
                   DisplayActor(theWnd,anActor);
                   anActor->SetVisibility(true);
                   aStudy->setVisibilityState(theEntry, Qtx::ShownState);
index a88c697..b6673af 100644 (file)
@@ -222,6 +222,10 @@ SMESHGUI_EXPORT
 
   SMESHGUI_EXPORT
   void UpdateActorsAfterUpdateStudy();
+
+  SMESHGUI_EXPORT
+  bool NoSmeshActors(SUIT_ViewWindow *theWnd=nullptr);
+
 };
 
 #endif // SMESHGUI_VTKUTILS_H
index d7d61bc..a667ba5 100644 (file)
@@ -1009,8 +1009,23 @@ void SMESH_Gen_i::UpdateIcons( SMESH::SMESH_Mesh_ptr theMesh )
         {
           SMESH::array_of_ElementType_var elemTypes = idSrc->GetTypes();
           isEmpty = ( elemTypes->length() == 0 );
+
+          if ( !isEmpty )
+          {
+            // check if all sub-shapes of sub-mesh on group are computed
+            // (pb: "Compute sub-mesh" menu is missing if a sub-mesh is partially computed)
+            SMESH::SMESH_subMesh_var subMesh = SMESH::SMESH_subMesh::_narrow( obj );
+            if ( !subMesh->_is_nil() )
+              if ( SMESH_subMesh* sm = mesh_i->GetImpl().GetSubMeshContaining( subMesh->GetId() ))
+                if ( sm->IsComputedPartially() )
+                {
+                  SetPixMap( so, "ICON_SMESH_TREE_MESH_PARTIAL" );
+                  continue;
+                }
+          }
         }
       }
+
       if ( isEmpty )
         SetPixMap( so, "ICON_SMESH_TREE_MESH_WARN");
       else if ( !isGroup )
@@ -1019,8 +1034,9 @@ void SMESH_Gen_i::UpdateIcons( SMESH::SMESH_Mesh_ptr theMesh )
         SetPixMap( so, "ICON_SMESH_TREE_GROUP_ON_FILTER" );
       else
         SetPixMap( so, "ICON_SMESH_TREE_GROUP" );
-    }
-  }
+
+    } // loop on sub-meshes or groups
+  } // loop on roots
 }
 
 //=======================================================================
index 16cc200..3330950 100644 (file)
@@ -1966,6 +1966,8 @@ void SMESH_MeshEditor_i::QuadTo4Tri (SMESH::SMESH_IDSource_ptr theObject)
   getEditor().QuadTo4Tri( faces );
   TPythonDump() << this << ".QuadTo4Tri( " << theObject << " )";
 
+  declareMeshModified( /*isReComputeSafe=*/false );
+
   SMESH_CATCH( SMESH::throwCorbaException );
 }
 
index 8a4313d..8455f6b 100644 (file)
@@ -649,11 +649,12 @@ SMESH_Mesh_i::AddHypothesis(GEOM::GEOM_Object_ptr       aSubShape,
   throw(SALOME::SALOME_Exception)
 {
   Unexpect aCatch(SALOME_SalomeException);
+
+  const int prevNbMeshEnt = NbNodes() + NbElements();
+
   if ( _preMeshInfo )
     _preMeshInfo->ForgetOrLoad();
 
-  const int prevNbMeshEnt = _impl->NbNodes() + _impl->GetMeshDS()->NbElements();
-
   std::string error;
   SMESH_Hypothesis::Hypothesis_Status status = addHypothesis( aSubShape, anHyp, &error );
   anErrorText = error.c_str();
index 0759332..c2f0ed0 100644 (file)
@@ -1900,6 +1900,12 @@ class StdMeshersBuilder_Cartesian_3D(Mesh_Algorithm):
                         points dividing the whole shape into ranges where the functions apply; points
                         coordinates should vary within (0.0, 1.0) range. Parameter *t* of the spacing
                         function f(t) varies from 0.0 to 1.0 within a shape range. 
+        Note: 
+            The actual grid spacing can slightly differ from the defined one. This is done for the
+            best fitting of polyhedrons and for a better mesh quality on the interval boundaries.
+            For example, if a constant **Spacing** is defined along an axis, the actual grid will
+            fill the shape's dimension L along this axis with round number of equal cells:
+            Spacing_actual = L / round( L / Spacing_defined ).
 
         Examples:
             "10.5" - defines a grid with a constant spacing
index b40bc6d..c99e958 100644 (file)
@@ -4450,7 +4450,7 @@ class Mesh(metaclass = MeshMeta):
 
         Returns:
              A list of edge groups and a list of corresponding node groups,
-             where the group is a list of IDs of edges or elements, like follows
+             where the group is a list of IDs of edges or nodes, like follows
              [[[branch_edges_1],[branch_edges_2]], [[branch_nodes_1],[branch_nodes_2]]].
              If a group is closed, the first and last nodes of the group are same.
         """
index e3d59a7..af0ea24 100644 (file)
@@ -200,22 +200,37 @@ namespace // INTERNAL STUFF
     if ( getBox()->IsOut( point ))
       return false;
 
+    bool ok = false;
+    double dist2, param;
+    distance2 = Precision::Infinite();
+
     if ( isLeaf() )
     {
       for ( size_t i = 0; i < _segments.size(); ++i )
         if ( !_segments[i].IsOut( point ) &&
-             _segments[i].IsOn( point, distance2, u ))
-          return true;
+             _segments[i].IsOn( point, dist2, param ) &&
+             dist2 < distance2 )
+        {
+          distance2 = dist2;
+          u         = param;
+          ok        = true;
+        }
+      return ok;
     }
     else
     {
       for (int i = 0; i < 8; i++)
-        if (((CurveProjector*) myChildren[i])->IsOnCurve( point, distance2, u ))
-          return true;
+        if (((CurveProjector*) myChildren[i])->IsOnCurve( point, dist2, param ) &&
+            dist2 < distance2 )
+        {
+          distance2 = dist2;
+          u         = param;
+          ok        = true;
+        }
     }
-    return false;
+    return ok;
   }
-  
+
   //================================================================================
   /*!
    * \brief Initialize
@@ -233,13 +248,13 @@ namespace // INTERNAL STUFF
     _pLast   = pl;
     _curve   = curve;
     _length2 = pf.SquareDistance( pl );
+    _line.SetLocation( pf );
+    _line.SetDirection( gp_Vec( pf, pl ));
     _chord2  = Max( _line.     SquareDistance( curve->Value( uf + 0.25 * ( ul - uf ))),
                     Max( _line.SquareDistance( curve->Value( uf + 0.5  * ( ul - uf ))),
                          _line.SquareDistance( curve->Value( uf + 0.75 * ( ul - uf )))));
     _chord2  = Max( tol, _chord2 );
     _chord   = Sqrt( _chord2 );
-    _line.SetLocation( pf );
-    _line.SetDirection( gp_Vec( pf, pl ));
 
     Bnd_Box bb;
     BndLib_Add3dCurve::Add( GeomAdaptor_Curve( curve, uf, ul ), tol, bb );
@@ -268,12 +283,12 @@ namespace // INTERNAL STUFF
       gp_Vec edge( _pFirst, _pLast );
       gp_Vec n1p ( _pFirst, point  );
       u = ( edge * n1p ) / _length2; // param [0,1] on the edge
-      if ( u < 0 )
+      if ( u < 0. )
       {
         if ( _pFirst.SquareDistance( point ) > _chord2 )
           return false;
       }
-      else if ( u > _chord )
+      else if ( u > 1. )
       {
         if ( _pLast.SquareDistance( point ) > _chord2 )
           return false;
index 4f4cf21..b35e76a 100644 (file)
@@ -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();
@@ -530,6 +675,22 @@ namespace {
 
   //================================================================================
   /*!
+   * \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
    */
   //================================================================================
@@ -559,6 +720,7 @@ namespace {
     }
 #endif
   }
+
 } // namespace
 
 //=======================================================================
@@ -617,6 +779,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 +791,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 +849,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 +873,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 +923,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 +953,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 ))
                 {
-                  meshedFaces.push_front( prism.myTop );
-                  meshedFaces.push_front( prism.myBottom );
-                  selectBottom = false;
+                  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_back( prism.myBottom );
+                  if ( prism.myAlgoSM && prism.myAlgoSM->GetAlgo() )
+                    meshedFace2AlgoSM.Bind( prism.myBottom, prism.myAlgoSM );
                 }
-                meshedPrism.push_back( prism );
-                meshedSolids.Add( solid );
               }
               InitComputeError();
             }
@@ -846,7 +1040,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 +1113,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;
@@ -1400,8 +1594,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 +1621,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 +1629,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 +1668,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 ));
@@ -2674,6 +2877,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 );
@@ -3339,6 +3545,7 @@ namespace Prism_3D
     myBottomEdges.clear();
     myNbEdgesInWires.clear();
     myWallQuads.clear();
+    myAlgoSM = nullptr;
   }
 
   //================================================================================
@@ -4641,7 +4848,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();
index d910bdd..850e01e 100644 (file)
@@ -106,6 +106,7 @@ namespace Prism_3D
     std::list< int >         myNbEdgesInWires;
 
     bool                     myNotQuadOnTop;
+    mutable SMESH_subMesh*   myAlgoSM; // sub-mesh with algo which computed myBottom
 
     size_t NbWires() const { return myNbEdgesInWires.size(); }