From: rnv Date: Thu, 19 Nov 2020 00:35:20 +0000 (+0300) Subject: Merge branch 'master' of https://codev-tuleap.cea.fr/plugins/git/salome/smesh X-Git-Tag: V9_7_0a1~48 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=982a098136211f1f96f26b2b48489bf862189cfa;hp=a0b14f92a46d5733c346df9b0f2bb2ee7be538b6;p=modules%2Fsmesh.git Merge branch 'master' of https://codev-tuleap.cea.fr/plugins/git/salome/smesh --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e6839abd..adfdf638c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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}) diff --git a/doc/salome/gui/SMESH/input/define_mesh_by_script.rst b/doc/salome/gui/SMESH/input/define_mesh_by_script.rst index 92387778c..43d7f89af 100644 --- a/doc/salome/gui/SMESH/input/define_mesh_by_script.rst +++ b/doc/salome/gui/SMESH/input/define_mesh_by_script.rst @@ -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 ` algorithm for construction of a 2D mesh using Python commands. diff --git a/src/SMESH/SMESH_Algo.cxx b/src/SMESH/SMESH_Algo.cxx index d4930818e..bdc93b1a1 100644 --- a/src/SMESH/SMESH_Algo.cxx +++ b/src/SMESH/SMESH_Algo.cxx @@ -950,10 +950,9 @@ void SMESH_Algo::InitComputeError() { _error = COMPERR_OK; _comment.clear(); - list::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(); } } diff --git a/src/SMESH/SMESH_Gen.cxx b/src/SMESH/SMESH_Gen.cxx index f00d3a4d5..663531180 100644 --- a/src/SMESH/SMESH_Gen.cxx +++ b/src/SMESH/SMESH_Gen.cxx @@ -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() ); } } diff --git a/src/SMESH/SMESH_Gen.hxx b/src/SMESH/SMESH_Gen.hxx index c94693a0e..e73fe6175 100644 --- a/src/SMESH/SMESH_Gen.hxx +++ b/src/SMESH/SMESH_Gen.hxx @@ -42,6 +42,7 @@ #include #include +#include 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); diff --git a/src/SMESH/SMESH_HypoFilter.cxx b/src/SMESH/SMESH_HypoFilter.cxx index e1100ac8f..ecbd64bdc 100644 --- a/src/SMESH/SMESH_HypoFilter.cxx +++ b/src/SMESH/SMESH_HypoFilter.cxx @@ -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() diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index ae3b70321..1d679c2bc 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -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( 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 ); } } } diff --git a/src/SMESH/SMESH_subMesh.cxx b/src/SMESH/SMESH_subMesh.cxx index 63344a509..4f8a56e85 100644 --- a/src/SMESH/SMESH_subMesh.cxx +++ b/src/SMESH/SMESH_subMesh.cxx @@ -110,6 +110,7 @@ SMESH_subMesh::SMESH_subMesh(int Id, } _computeCost = 0; // how costly is to compute this sub-mesh _realComputeCost = 0; + _allowedSubShapes = nullptr; } //============================================================================= @@ -1478,11 +1479,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 +1614,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 +1752,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 +2147,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 ); diff --git a/src/SMESH/SMESH_subMesh.hxx b/src/SMESH/SMESH_subMesh.hxx index 03dd98e49..6b610ea1d 100644 --- a/src/SMESH/SMESH_subMesh.hxx +++ b/src/SMESH/SMESH_subMesh.hxx @@ -36,6 +36,7 @@ #include "Utils_SALOME_Exception.hxx" #include +#include #include #include @@ -256,6 +257,12 @@ public: bool IsMeshComputed() const; // check if _subMeshDS contains mesh elements unless _alwaysComputed==true + /*! + * \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 +351,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 diff --git a/src/SMESHGUI/SMESHGUI_MeshOrderOp.cxx b/src/SMESHGUI/SMESHGUI_MeshOrderOp.cxx index 2c17777a5..4f459d435 100644 --- a/src/SMESHGUI/SMESHGUI_MeshOrderOp.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshOrderOp.cxx @@ -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"; } //================================================================================ diff --git a/src/SMESH_I/SMESH_MeshEditor_i.cxx b/src/SMESH_I/SMESH_MeshEditor_i.cxx index 16cc20053..3330950a2 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.cxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx @@ -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 ); } diff --git a/src/SMESH_I/SMESH_Mesh_i.cxx b/src/SMESH_I/SMESH_Mesh_i.cxx index 8a4313de5..8455f6b46 100644 --- a/src/SMESH_I/SMESH_Mesh_i.cxx +++ b/src/SMESH_I/SMESH_Mesh_i.cxx @@ -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(); diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index b40bc6d1e..c99e95821 100644 --- a/src/SMESH_SWIG/smeshBuilder.py +++ b/src/SMESH_SWIG/smeshBuilder.py @@ -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. """ diff --git a/src/StdMeshers/StdMeshers_Import_1D.cxx b/src/StdMeshers/StdMeshers_Import_1D.cxx index e3d59a79c..af0ea24bd 100644 --- a/src/StdMeshers/StdMeshers_Import_1D.cxx +++ b/src/StdMeshers/StdMeshers_Import_1D.cxx @@ -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; diff --git a/src/StdMeshers/StdMeshers_Prism_3D.cxx b/src/StdMeshers/StdMeshers_Prism_3D.cxx index 4f4cf213b..b35e76ae3 100644 --- a/src/StdMeshers/StdMeshers_Prism_3D.cxx +++ b/src/StdMeshers/StdMeshers_Prism_3D.cxx @@ -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(); @@ -528,6 +673,22 @@ namespace { return nbSides; } + //================================================================================ + /*! + * \brief Count EDGEs ignoring degenerated ones + */ + //================================================================================ + + int CountEdges( const TopoDS_Face& face ) + { + int nbE = 0; + for ( TopExp_Explorer edgeExp( face, TopAbs_EDGE ); edgeExp.More(); edgeExp.Next() ) + if ( !SMESH_Algo::isDegenerated( TopoDS::Edge( edgeExp.Current() ))) + ++nbE; + + return nbE; + } + //================================================================================ /*! * \brief Set/get wire index to FaceQuadStruct @@ -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(); diff --git a/src/StdMeshers/StdMeshers_Prism_3D.hxx b/src/StdMeshers/StdMeshers_Prism_3D.hxx index d910bdd27..850e01ee0 100644 --- a/src/StdMeshers/StdMeshers_Prism_3D.hxx +++ b/src/StdMeshers/StdMeshers_Prism_3D.hxx @@ -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(); }