X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FSMESH%2FSMESH_subMesh.cxx;h=a3b12c77e5da711defef4ca81fc533a19f275ea2;hp=bbb5fa96a45e3c7f8c7e2da6dcaf1b826d6c1252;hb=5552aec787c289730a35843d295811cfdadaacd3;hpb=79b1ac2b6df9117f16f11d444b1f165d477a1813 diff --git a/src/SMESH/SMESH_subMesh.cxx b/src/SMESH/SMESH_subMesh.cxx index bbb5fa96a..a3b12c77e 100644 --- a/src/SMESH/SMESH_subMesh.cxx +++ b/src/SMESH/SMESH_subMesh.cxx @@ -1,62 +1,71 @@ -// SMESH SMESH : implementaion of SMESH idl descriptions +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS // -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License. +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. // -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. // +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + +// SMESH SMESH : implementation of SMESH idl descriptions // File : SMESH_subMesh.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ #include "SMESH_subMesh.hxx" +#include "SMDS_SetIterator.hxx" +#include "SMESHDS_Mesh.hxx" #include "SMESH_Algo.hxx" +#include "SMESH_Comment.hxx" #include "SMESH_Gen.hxx" #include "SMESH_HypoFilter.hxx" #include "SMESH_Hypothesis.hxx" #include "SMESH_Mesh.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_subMeshEventListener.hxx" -#include "SMESH_Comment.hxx" -#include "SMDS_SetIterator.hxx" #include "utilities.h" #include "OpUtil.hxx" +#include "Basics_Utils.hxx" #include #include #include +#include #include #include +#include #include #include -#include -#include #include +#include #include #include +#include + using namespace std; +#ifdef _DEBUG_ +// enable printing algo + shape id + hypo used while meshing +//#define PRINT_WHO_COMPUTE_WHAT +#endif + //============================================================================= /*! * \brief Allocate some memory at construction and release it at destruction. @@ -83,22 +92,24 @@ SMESH_subMesh::SMESH_subMesh(int Id, SMESHDS_Mesh * meshDS, const TopoDS_Shape & aSubShape) { - _subShape = aSubShape; - _subMeshDS = meshDS->MeshElements(_subShape); // may be null ... - _father = father; - _Id = Id; - _dependenceAnalysed = _alwaysComputed = false; - - if (_subShape.ShapeType() == TopAbs_VERTEX) - { - _algoState = HYP_OK; - _computeState = READY_TO_COMPUTE; - } - else - { - _algoState = NO_ALGO; - _computeState = NOT_READY; - } + _subShape = aSubShape; + _subMeshDS = meshDS->MeshElements(_subShape); // may be null ... + _father = father; + _Id = Id; + _dependenceAnalysed = _alwaysComputed = false; + _algo = 0; + if (_subShape.ShapeType() == TopAbs_VERTEX) + { + _algoState = HYP_OK; + _computeState = READY_TO_COMPUTE; + } + else + { + _algoState = NO_ALGO; + _computeState = NOT_READY; + } + _computeCost = 0; // how costly is to compute this sub-mesh + _realComputeCost = 0; } //============================================================================= @@ -109,9 +120,7 @@ SMESH_subMesh::SMESH_subMesh(int Id, SMESH_subMesh::~SMESH_subMesh() { - MESSAGE("SMESH_subMesh::~SMESH_subMesh"); - // **** - DeleteOwnListeners(); + deleteOwnListeners(); } //============================================================================= @@ -144,6 +153,17 @@ SMESHDS_SubMesh * SMESH_subMesh::GetSubMeshDS() */ //============================================================================= +const SMESHDS_SubMesh * SMESH_subMesh::GetSubMeshDS() const +{ + return ((SMESH_subMesh*) this )->GetSubMeshDS(); +} + +//============================================================================= +/*! + * + */ +//============================================================================= + SMESHDS_SubMesh* SMESH_subMesh::CreateSubMeshDS() { if ( !GetSubMeshDS() ) { @@ -172,7 +192,23 @@ SMESH_subMesh *SMESH_subMesh::GetFirstToCompute() //================================================================================ /*! - * \brief Allow algo->Compute() if a subshape of lower dim is meshed but + * \brief Returns a current algorithm + */ +//================================================================================ + +SMESH_Algo* SMESH_subMesh::GetAlgo() const +{ + if ( !_algo ) + { + SMESH_subMesh* me = const_cast< SMESH_subMesh* >( this ); + me->_algo = _father->GetGen()->GetAlgo( me ); + } + return _algo; +} + +//================================================================================ +/*! + * \brief Allow algo->Compute() if a sub-shape of lower dim is meshed but * none mesh entity is bound to it (PAL13615, 2nd part) */ //================================================================================ @@ -186,6 +222,19 @@ void SMESH_subMesh::SetIsAlwaysComputed(bool isAlCo) ComputeStateEngine( CHECK_COMPUTE_STATE ); } +//======================================================================= +/*! + * \brief Return true if no mesh entities is bound to the submesh + */ +//======================================================================= + +bool SMESH_subMesh::IsEmpty() const +{ + if (SMESHDS_SubMesh * subMeshDS = ((SMESH_subMesh*)this)->GetSubMeshDS()) + return (!subMeshDS->NbElements() && !subMeshDS->NbNodes()); + return true; +} + //======================================================================= //function : IsMeshComputed //purpose : check if _subMeshDS contains mesh elements @@ -195,7 +244,7 @@ bool SMESH_subMesh::IsMeshComputed() const { if ( _alwaysComputed ) return true; - // algo may bind a submesh not to _subShape, eg 3D algo + // algo may bind a sub-mesh not to _subShape, eg 3D algo // sets nodes on SHELL while _subShape may be SOLID SMESHDS_Mesh* meshDS = _father->GetMeshDS(); @@ -224,16 +273,17 @@ bool SMESH_subMesh::IsMeshComputed() const //============================================================================= /*! - * + * Return true if all sub-meshes have been meshed */ //============================================================================= -bool SMESH_subMesh::SubMeshesComputed() +bool SMESH_subMesh::SubMeshesComputed(bool * isFailedToCompute/*=0*/) const { int myDim = SMESH_Gen::GetShapeDim( _subShape ); int dimToCheck = myDim - 1; bool subMeshesComputed = true; - // check subMeshes with upper dimension => reverse iteration + if ( isFailedToCompute ) *isFailedToCompute = false; + // check sub-meshes with upper dimension => reverse iteration SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,true); while ( smIt->more() ) { @@ -241,287 +291,256 @@ bool SMESH_subMesh::SubMeshesComputed() if ( sm->_alwaysComputed ) continue; const TopoDS_Shape & ss = sm->GetSubShape(); + // MSV 07.04.2006: restrict checking to myDim-1 only. Ex., there is no sense // in checking of existence of edges if the algo needs only faces. Moreover, - // degenerated edges may have no submesh, as after computing NETGEN_2D. - int dim = SMESH_Gen::GetShapeDim( ss ); - if (dim < dimToCheck) - break; // the rest subMeshes are all of less dimension + // degenerated edges may have no sub-mesh, as after computing NETGEN_2D. + if ( !_algo || _algo->NeedDiscreteBoundary() ) { + int dim = SMESH_Gen::GetShapeDim( ss ); + if (dim < dimToCheck) + break; // the rest sub-meshes are all of less dimension + } SMESHDS_SubMesh * ds = sm->GetSubMeshDS(); - bool computeOk = (sm->GetComputeState() == COMPUTE_OK || - (ds && ( ds->NbNodes() || ds->NbElements() ))); + bool computeOk = ((sm->GetComputeState() == COMPUTE_OK ) || + (ds && ( dimToCheck ? ds->NbElements() : ds->NbNodes() ))); if (!computeOk) { - int type = ss.ShapeType(); - subMeshesComputed = false; - switch (type) - { - case TopAbs_COMPOUND: - { - MESSAGE("The not computed sub mesh is a COMPOUND"); - break; - } - case TopAbs_COMPSOLID: - { - MESSAGE("The not computed sub mesh is a COMPSOLID"); - break; - } - case TopAbs_SHELL: - { - MESSAGE("The not computed sub mesh is a SHEL"); - break; - } - case TopAbs_WIRE: - { - MESSAGE("The not computed sub mesh is a WIRE"); - break; - } - case TopAbs_SOLID: - { - MESSAGE("The not computed sub mesh is a SOLID"); - break; - } - case TopAbs_FACE: - { - MESSAGE("The not computed sub mesh is a FACE"); - break; - } - case TopAbs_EDGE: - { - MESSAGE("The not computed sub mesh is a EDGE"); - break; - } - default: - { - MESSAGE("The not computed sub mesh is of unknown type"); - break; - } - } + if ( isFailedToCompute && !(*isFailedToCompute) ) + *isFailedToCompute = ( sm->GetComputeState() == FAILED_TO_COMPUTE ); - break; + if ( !isFailedToCompute ) + break; } } return subMeshesComputed; } -//============================================================================= +//================================================================================ /*! - * + * \brief Return cost of computing this sub-mesh. If hypotheses are not well defined, + * zero is returned + * \return int - the computation cost in abstract units. */ -//============================================================================= +//================================================================================ -bool SMESH_subMesh::SubMeshesReady() +int SMESH_subMesh::GetComputeCost() const { - bool subMeshesReady = true; - SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,true); - while ( smIt->more() ) { - SMESH_subMesh *sm = smIt->next(); - bool computeOk = (sm->GetComputeState() == COMPUTE_OK || - sm->GetComputeState() == READY_TO_COMPUTE); - if (!computeOk) - { - subMeshesReady = false; - SCRUTE(sm->GetId()); - break; + return _realComputeCost; +} + +//================================================================================ +/*! + * \brief Return cost of computing this sub-mesh. The cost depends on the shape type + * and number of sub-meshes this one DependsOn(). + * \return int - the computation cost in abstract units. + */ +//================================================================================ + +int SMESH_subMesh::computeCost() const +{ + if ( !_computeCost ) + { + int computeCost; + switch ( _subShape.ShapeType() ) { + case TopAbs_SOLID: + case TopAbs_SHELL: computeCost = 5000; break; + case TopAbs_FACE: computeCost = 500; break; + case TopAbs_EDGE: computeCost = 2; break; + default: computeCost = 1; } + SMESH_subMeshIteratorPtr childIt = getDependsOnIterator(/*includeSelf=*/false); + while ( childIt->more() ) + computeCost += childIt->next()->computeCost(); + + ((SMESH_subMesh*)this)->_computeCost = computeCost; } - return subMeshesReady; + return _computeCost; } //============================================================================= /*! - * Construct dependence on first level subMeshes. complex shapes (compsolid, - * shell, wire) are not analysed the same way as simple shapes (solid, face, - * edge). - * For collection shapes (compsolid, shell, wire) prepare a list of submeshes - * with possible multiples occurences. Multiples occurences corresponds to - * internal frontiers within shapes of the collection and must not be keeped. - * See FinalizeDependence. + * Returns all sub-meshes this one depend on */ //============================================================================= const map < int, SMESH_subMesh * >& SMESH_subMesh::DependsOn() { - if (_dependenceAnalysed) + if ( _dependenceAnalysed || !_father->HasShapeToMesh() ) return _mapDepend; - //MESSAGE("SMESH_subMesh::DependsOn"); - int type = _subShape.ShapeType(); - //SCRUTE(type); switch (type) { case TopAbs_COMPOUND: + { + list< TopoDS_Shape > compounds( 1, _subShape ); + list< TopoDS_Shape >::iterator comp = compounds.begin(); + for ( ; comp != compounds.end(); ++comp ) { - //MESSAGE("compound"); - for (TopExp_Explorer exp(_subShape, TopAbs_SOLID); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); - } - for (TopExp_Explorer exp(_subShape, TopAbs_SHELL, TopAbs_SOLID); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); //only shell not in solid - } - for (TopExp_Explorer exp(_subShape, TopAbs_FACE, TopAbs_SHELL); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); - } - for (TopExp_Explorer exp(_subShape, TopAbs_EDGE, TopAbs_FACE); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); - } - break; - } - case TopAbs_COMPSOLID: - { - //MESSAGE("compsolid"); - for (TopExp_Explorer exp(_subShape, TopAbs_SOLID); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); - } - break; - } - case TopAbs_SHELL: - { - //MESSAGE("shell"); - for (TopExp_Explorer exp(_subShape, TopAbs_FACE); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); - } - break; - } - case TopAbs_WIRE: - { - //MESSAGE("wire"); - for (TopExp_Explorer exp(_subShape, TopAbs_EDGE); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); - } - break; - } - case TopAbs_SOLID: - { - //MESSAGE("solid"); - if(_father->HasShapeToMesh()) { - for (TopExp_Explorer exp(_subShape, TopAbs_FACE); exp.More(); - exp.Next()) + for ( TopoDS_Iterator sub( *comp ); sub.More(); sub.Next() ) + switch ( sub.Value().ShapeType() ) { - InsertDependence(exp.Current()); + case TopAbs_COMPOUND: compounds.push_back( sub.Value() ); break; + case TopAbs_COMPSOLID: insertDependence( sub.Value(), TopAbs_SOLID ); break; + case TopAbs_SOLID: insertDependence( sub.Value(), TopAbs_SOLID ); break; + case TopAbs_SHELL: insertDependence( sub.Value(), TopAbs_FACE ); break; + case TopAbs_FACE: insertDependence( sub.Value(), TopAbs_FACE ); break; + case TopAbs_WIRE: insertDependence( sub.Value(), TopAbs_EDGE ); break; + case TopAbs_EDGE: insertDependence( sub.Value(), TopAbs_EDGE ); break; + case TopAbs_VERTEX: insertDependence( sub.Value(), TopAbs_VERTEX ); break; + default:; } - } - break; - } - case TopAbs_FACE: - { - //MESSAGE("face"); - for (TopExp_Explorer exp(_subShape, TopAbs_EDGE); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); - } - break; - } - case TopAbs_EDGE: - { - //MESSAGE("edge"); - for (TopExp_Explorer exp(_subShape, TopAbs_VERTEX); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); - } - break; - } - case TopAbs_VERTEX: - { - break; - } - default: - { - break; } } + break; + case TopAbs_COMPSOLID: insertDependence( _subShape, TopAbs_SOLID ); break; + case TopAbs_SOLID: insertDependence( _subShape, TopAbs_FACE ); + { /*internal EDGE*/ insertDependence( _subShape, TopAbs_EDGE, TopAbs_WIRE ); break; } + case TopAbs_SHELL: insertDependence( _subShape, TopAbs_FACE ); break; + case TopAbs_FACE: insertDependence( _subShape, TopAbs_EDGE ); break; + case TopAbs_WIRE: insertDependence( _subShape, TopAbs_EDGE ); break; + case TopAbs_EDGE: insertDependence( _subShape, TopAbs_VERTEX ); break; + default:; + } _dependenceAnalysed = true; return _mapDepend; } +//================================================================================ +/*! + * \brief Return a key for SMESH_subMesh::_mapDepend map + */ +//================================================================================ + +namespace +{ + int dependsOnMapKey( TopAbs_ShapeEnum type, int shapeID ) + { + int ordType = 9 - int(type); // 2 = Vertex, 8 = CompSolid + int cle = shapeID; + cle += 10000000 * ordType; // sort map by ordType then index + return cle; + } + int dependsOnMapKey( const SMESH_subMesh* sm ) + { + return dependsOnMapKey( sm->GetSubShape().ShapeType(), sm->GetId() ); + } +} + //============================================================================= /*! - * For simple Shapes (solid, face, edge): add subMesh into dependence list. + * Add sub-meshes on sub-shapes of a given type into the dependence map. */ //============================================================================= -void SMESH_subMesh::InsertDependence(const TopoDS_Shape aSubShape) +void SMESH_subMesh::insertDependence(const TopoDS_Shape aShape, + TopAbs_ShapeEnum aSubType, + TopAbs_ShapeEnum avoidType) { - //MESSAGE("SMESH_subMesh::InsertDependence"); - SMESH_subMesh *aSubMesh = _father->GetSubMesh(aSubShape); - int type = aSubShape.ShapeType(); - int ordType = 9 - type; // 2 = Vertex, 8 = CompSolid - int cle = aSubMesh->GetId(); - cle += 10000000 * ordType; // sort map by ordType then index - if ( _mapDepend.find( cle ) == _mapDepend.end()) + TopExp_Explorer sub( aShape, aSubType, avoidType ); + for ( ; sub.More(); sub.Next() ) { - _mapDepend[cle] = aSubMesh; - const map < int, SMESH_subMesh * > & subMap = aSubMesh->DependsOn(); - _mapDepend.insert( subMap.begin(), subMap.end() ); + SMESH_subMesh *aSubMesh = _father->GetSubMesh( sub.Current() ); + if ( aSubMesh->GetId() == 0 ) + continue; // not a sub-shape of the shape to mesh + int cle = dependsOnMapKey( aSubMesh ); + if ( _mapDepend.find( cle ) == _mapDepend.end()) + { + _mapDepend[cle] = aSubMesh; + const map < int, SMESH_subMesh * > & subMap = aSubMesh->DependsOn(); + _mapDepend.insert( subMap.begin(), subMap.end() ); + } } } +//================================================================================ +/*! + * \brief Return \c true if \a this sub-mesh depends on \a other + */ +//================================================================================ + +bool SMESH_subMesh::DependsOn( const SMESH_subMesh* other ) const +{ + return other ? _mapDepend.count( dependsOnMapKey( other )) : false; +} + +//================================================================================ +/*! + * \brief Return \c true if \a this sub-mesh depends on a \a shape + */ +//================================================================================ + +bool SMESH_subMesh::DependsOn( const int shapeID ) const +{ + return DependsOn( _father->GetSubMeshContaining( shapeID )); +} + //============================================================================= /*! - * + * Return a shape of \a this sub-mesh */ //============================================================================= const TopoDS_Shape & SMESH_subMesh::GetSubShape() const { - //MESSAGE("SMESH_subMesh::GetSubShape"); - return _subShape; + return _subShape; } - //======================================================================= //function : CanAddHypothesis //purpose : return true if theHypothesis can be attached to me: -// its dimention is checked +// its dimension is checked //======================================================================= bool SMESH_subMesh::CanAddHypothesis(const SMESH_Hypothesis* theHypothesis) const { int aHypDim = theHypothesis->GetDim(); - if(_father->HasShapeToMesh()) { - int aShapeDim = SMESH_Gen::GetShapeDim(_subShape); - if ( aHypDim <= aShapeDim ) - return true; - } - else - //Only 3D hypothesis may be assigned to the mesh w/o geometry - return aHypDim == 3; -// if ( aHypDim < aShapeDim ) -// return ( _father->IsMainShape( _subShape )); + int aShapeDim = SMESH_Gen::GetShapeDim(_subShape); + // issue 21106. Forbid 3D mesh on the SHELL + // if (aHypDim == 3 && aShapeDim == 3) { + // // check case of open shell + // //if (_subShape.ShapeType() == TopAbs_SHELL && !_subShape.Closed()) + // if (_subShape.ShapeType() == TopAbs_SHELL && !BRep_Tool::IsClosed(_subShape)) + // return false; + // } + if ( aHypDim <= aShapeDim ) + return true; return false; } //======================================================================= -//function : IsApplicableHypotesis -//purpose : +//function : IsApplicableHypothesis +//purpose : check if this sub-mesh can be computed using a hypothesis +//======================================================================= + +bool SMESH_subMesh::IsApplicableHypothesis(const SMESH_Hypothesis* theHypothesis) const +{ + if ( !_father->HasShapeToMesh() && _subShape.ShapeType() == TopAbs_SOLID ) + return true; // true for the PseudoShape + + return IsApplicableHypothesis( theHypothesis, _subShape.ShapeType() ); +} + +//======================================================================= +//function : IsApplicableHypothesis +//purpose : compare shape type and hypothesis type //======================================================================= -bool SMESH_subMesh::IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis, - const TopAbs_ShapeEnum theShapeType) +bool SMESH_subMesh::IsApplicableHypothesis(const SMESH_Hypothesis* theHypothesis, + const TopAbs_ShapeEnum theShapeType) { if ( theHypothesis->GetType() > SMESHDS_Hypothesis::PARAM_ALGO) + { // algorithm - return ( theHypothesis->GetShapeType() & (1<< theShapeType)); + if ( theHypothesis->GetShapeType() & (1<< theShapeType)) + // issue 21106. Forbid 3D mesh on the SHELL + return !( theHypothesis->GetDim() == 3 && theShapeType == TopAbs_SHELL ); + else + return false; + } // hypothesis switch ( theShapeType ) { @@ -548,28 +567,31 @@ bool SMESH_subMesh::IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis, return false; } -//============================================================================= +//================================================================================ /*! - * + * \brief Treats modification of hypotheses definition + * \param [in] event - what happens + * \param [in] anHyp - a hypothesis + * \return SMESH_Hypothesis::Hypothesis_Status - a treatment result. + * + * Optional description of a problematic situation (if any) can be retrieved + * via GetComputeError(). */ -//============================================================================= +//================================================================================ SMESH_Hypothesis::Hypothesis_Status - SMESH_subMesh::AlgoStateEngine(int event, SMESH_Hypothesis * anHyp) + SMESH_subMesh::AlgoStateEngine(algo_event event, SMESH_Hypothesis * anHyp) { - // MESSAGE("SMESH_subMesh::AlgoStateEngine"); - //SCRUTE(_algoState); - //SCRUTE(event); - // **** les retour des evenement shape sont significatifs // (add ou remove fait ou non) // le retour des evenement father n'indiquent pas que add ou remove fait SMESH_Hypothesis::Hypothesis_Status aux_ret, ret = SMESH_Hypothesis::HYP_OK; + if ( _Id == 0 ) return ret; // not a sub-shape of the shape to mesh SMESHDS_Mesh* meshDS =_father->GetMeshDS(); - SMESH_Gen* gen =_father->GetGen(); SMESH_Algo* algo = 0; + _algo = 0; if (_subShape.ShapeType() == TopAbs_VERTEX ) { @@ -585,7 +607,7 @@ SMESH_Hypothesis::Hypothesis_Status if ( event != REMOVE_FATHER_ALGO ) { _algoState = NO_ALGO; - algo = gen->GetAlgo(*_father, _subShape); + algo = GetAlgo(); if ( algo ) { _algoState = MISSING_HYP; if ( event == REMOVE_FATHER_HYP || @@ -598,8 +620,9 @@ SMESH_Hypothesis::Hypothesis_Status int oldAlgoState = _algoState; bool modifiedHyp = (event == MODIF_HYP); // if set to true, force event MODIF_ALGO_STATE + SMESH_Algo* algoRequiringCleaning = 0; - bool isApplicableHyp = IsApplicableHypotesis( anHyp ); + bool isApplicableHyp = IsApplicableHypothesis( anHyp ); if (event == ADD_ALGO || event == ADD_FATHER_ALGO) { @@ -607,14 +630,23 @@ SMESH_Hypothesis::Hypothesis_Status // check if a shape needed by algo is present // ------------------------------------------- algo = static_cast< SMESH_Algo* >( anHyp ); - if(_father->GetShapeToMesh() != SMESH_Mesh::PseudoShape()) - if ( !_father->HasShapeToMesh() && algo->NeedShape() ) - return SMESH_Hypothesis::HYP_BAD_GEOMETRY; + if ( !_father->HasShapeToMesh() && algo->NeedShape() ) + return SMESH_Hypothesis::HYP_NEED_SHAPE; // ---------------------- // check mesh conformity // ---------------------- if (isApplicableHyp && !_father->IsNotConformAllowed() && !IsConform( algo )) return SMESH_Hypothesis::HYP_NOTCONFORM; + + // check if all-dimensional algo is hidden by other local one + if ( event == ADD_ALGO ) { + SMESH_HypoFilter filter( SMESH_HypoFilter::HasType( algo->GetType() )); + filter.Or( SMESH_HypoFilter::HasType( algo->GetType()+1 )); + filter.Or( SMESH_HypoFilter::HasType( algo->GetType()+2 )); + if ( SMESH_Algo * curAlgo = (SMESH_Algo*)_father->GetHypothesis( this, filter, true )) + if ( !curAlgo->NeedDiscreteBoundary() && curAlgo != anHyp ) + algoRequiringCleaning = curAlgo; + } } // ---------------------------------- @@ -625,18 +657,7 @@ SMESH_Hypothesis::Hypothesis_Status if ( ! CanAddHypothesis( anHyp )) // check dimension return SMESH_Hypothesis::HYP_BAD_DIM; - if(anHyp->GetDim() == 3 && !_father->HasShapeToMesh() - && event == ADD_ALGO) { - //Only NETGEN_3D and GHS3D_3D can be assigned to the Mesh w/o geometryy - bool isNetgen3D = (strcmp( "NETGEN_3D", anHyp->GetName()) == 0); - bool isGhs3d = (strcmp( "GHS3D_3D", anHyp->GetName()) == 0); - if( !isNetgen3D && !isGhs3d) - return SMESH_Hypothesis::HYP_BAD_DIM; - } - - - - if ( /*!anHyp->IsAuxiliary() &&*/ GetSimilarAttached( _subShape, anHyp ) ) + if ( !anHyp->IsAuxiliary() && getSimilarAttached( _subShape, anHyp ) ) return SMESH_Hypothesis::HYP_ALREADY_EXIST; if ( !meshDS->AddHypothesis(_subShape, anHyp)) @@ -654,16 +675,8 @@ SMESH_Hypothesis::Hypothesis_Status if (event == REMOVE_ALGO) { algo = dynamic_cast (anHyp); - if (!algo->NeedDescretBoundary()) - { - // clean all mesh in the tree of the current submesh; - // we must perform it now because later - // we will have no information about the type of the removed algo - CleanDependants(); - ComputeStateEngine( CLEAN ); - CleanDependsOn(); - ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE ); - } + if (!algo->NeedDiscreteBoundary()) + algoRequiringCleaning = algo; } } @@ -673,6 +686,9 @@ SMESH_Hypothesis::Hypothesis_Status if (!isApplicableHyp) return ret; // not applicable hypotheses do not change algo state + if (( algo = GetAlgo())) + algo->InitComputeError(); + switch (_algoState) { @@ -683,16 +699,16 @@ SMESH_Hypothesis::Hypothesis_Status case ADD_HYP: break; case ADD_ALGO: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if (algo->CheckHypothesis((*_father),_subShape, aux_ret)) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else if ( algo->IsStatusFatal( aux_ret )) { meshDS->RemoveHypothesis(_subShape, anHyp); ret = aux_ret; } else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); break; } case REMOVE_HYP: @@ -700,26 +716,26 @@ SMESH_Hypothesis::Hypothesis_Status case ADD_FATHER_HYP: break; case ADD_FATHER_ALGO: { // Algo just added in father - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if ( algo == anHyp ) { if ( algo->CheckHypothesis((*_father),_subShape, aux_ret)) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; } case REMOVE_FATHER_HYP: break; case REMOVE_FATHER_ALGO: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); if (algo) { if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; } @@ -736,10 +752,10 @@ SMESH_Hypothesis::Hypothesis_Status switch (event) { case ADD_HYP: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, ret )) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); if (SMESH_Hypothesis::IsStatusFatal( ret )) meshDS->RemoveHypothesis(_subShape, anHyp); else if (!_father->IsUsedHypothesis( anHyp, this )) @@ -750,70 +766,70 @@ SMESH_Hypothesis::Hypothesis_Status break; } case ADD_ALGO: { //already existing algo : on father ? - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))// ignore hyp status - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else if ( algo->IsStatusFatal( aux_ret )) { meshDS->RemoveHypothesis(_subShape, anHyp); ret = aux_ret; } else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); break; } case REMOVE_HYP: break; case REMOVE_ALGO: { // perhaps a father algo applies ? - algo = gen->GetAlgo((*_father), _subShape); - if (algo == NULL) // no more algo applying on subShape... + algo = GetAlgo(); + if (algo == NULL) // no more algo applying on sub-shape... { - SetAlgoState(NO_ALGO); + setAlgoState(NO_ALGO); } else { if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; } case MODIF_HYP: // assigned hypothesis value may become good case ADD_FATHER_HYP: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); break; } case ADD_FATHER_ALGO: { // new father algo - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT( algo ); if ( algo == anHyp ) { if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; } case REMOVE_FATHER_HYP: // nothing to do break; case REMOVE_FATHER_ALGO: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); if (algo == NULL) // no more applying algo on father { - SetAlgoState(NO_ALGO); + setAlgoState(NO_ALGO); } else { if ( algo->CheckHypothesis((*_father),_subShape , aux_ret )) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; } @@ -829,7 +845,7 @@ SMESH_Hypothesis::Hypothesis_Status switch (event) { case ADD_HYP: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if (!algo->CheckHypothesis((*_father),_subShape, ret )) { @@ -837,7 +853,7 @@ SMESH_Hypothesis::Hypothesis_Status // ret should be fatal: anHyp was not added ret = SMESH_Hypothesis::HYP_INCOMPATIBLE; } - else if (!_father->IsUsedHypothesis( anHyp, this )) + else if (!_father->IsUsedHypothesis( anHyp, this )) ret = SMESH_Hypothesis::HYP_INCOMPATIBLE; if (SMESH_Hypothesis::IsStatusFatal( ret )) @@ -852,37 +868,37 @@ SMESH_Hypothesis::Hypothesis_Status break; } case ADD_ALGO: { //already existing algo : on father ? - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) { // check if algo changes SMESH_HypoFilter f; f.Init( SMESH_HypoFilter::IsAlgo() ); f.And( SMESH_HypoFilter::IsApplicableTo( _subShape )); f.AndNot( SMESH_HypoFilter::Is( algo )); - const SMESH_Hypothesis * prevAlgo = _father->GetHypothesis( _subShape, f, true ); + const SMESH_Hypothesis * prevAlgo = _father->GetHypothesis( this, f, true ); if (prevAlgo && - string(algo->GetName()) != string(prevAlgo->GetName()) ) + string( algo->GetName()) != prevAlgo->GetName()) modifiedHyp = true; } else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); break; } case REMOVE_HYP: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); modifiedHyp = true; break; } case REMOVE_ALGO: { // perhaps a father algo applies ? - algo = gen->GetAlgo((*_father), _subShape); - if (algo == NULL) // no more algo applying on subShape... + algo = GetAlgo(); + if (algo == NULL) // no more algo applying on sub-shape... { - SetAlgoState(NO_ALGO); + setAlgoState(NO_ALGO); } else { @@ -892,13 +908,13 @@ SMESH_Hypothesis::Hypothesis_Status modifiedHyp = true; } else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; } case MODIF_HYP: // hypothesis value may become bad case ADD_FATHER_HYP: { // new father hypothesis ? - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) { @@ -906,11 +922,11 @@ SMESH_Hypothesis::Hypothesis_Status modifiedHyp = true; } else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); break; } case ADD_FATHER_ALGO: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); if ( algo == anHyp ) { // a new algo on father if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) { // check if algo changes @@ -918,33 +934,38 @@ SMESH_Hypothesis::Hypothesis_Status f.Init( SMESH_HypoFilter::IsAlgo() ); f.And( SMESH_HypoFilter::IsApplicableTo( _subShape )); f.AndNot( SMESH_HypoFilter::Is( algo )); - const SMESH_Hypothesis* prevAlgo = _father->GetHypothesis( _subShape, f, true ); + const SMESH_Hypothesis* prevAlgo = _father->GetHypothesis( this, f, true ); if (prevAlgo && string(algo->GetName()) != string(prevAlgo->GetName()) ) modifiedHyp = true; } else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; } case REMOVE_FATHER_HYP: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) { // is there the same local hyp or maybe a new father algo applied? - if ( !GetSimilarAttached( _subShape, anHyp ) ) + if ( !getSimilarAttached( _subShape, anHyp ) ) modifiedHyp = true; } else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); break; } case REMOVE_FATHER_ALGO: { - algo = gen->GetAlgo((*_father), _subShape); + // IPAL21346. Edges not removed when Netgen 1d-2d is removed from a SOLID. + // CLEAN was not called at event REMOVE_ALGO because the algo is not applicable to SOLID. + algo = dynamic_cast (anHyp); + if (!algo->NeedDiscreteBoundary()) + algoRequiringCleaning = algo; + algo = GetAlgo(); if (algo == NULL) // no more applying algo on father { - SetAlgoState(NO_ALGO); + setAlgoState(NO_ALGO); } else { @@ -954,7 +975,7 @@ SMESH_Hypothesis::Hypothesis_Status modifiedHyp = true; } else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; } @@ -973,36 +994,50 @@ SMESH_Hypothesis::Hypothesis_Status // detect algorithm hiding // - if ( ret == SMESH_Hypothesis::HYP_OK && - ( event == ADD_ALGO || event == ADD_FATHER_ALGO ) && + if ( ret == SMESH_Hypothesis::HYP_OK && + ( event == ADD_ALGO || event == ADD_FATHER_ALGO ) && algo && algo->GetName() == anHyp->GetName() ) { // is algo hidden? SMESH_Gen* gen = _father->GetGen(); - TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape )); - for ( ; ( ret == SMESH_Hypothesis::HYP_OK && it.More()); it.Next() ) { - if ( SMESH_Algo* upperAlgo = gen->GetAlgo( *_father, it.Value() )) - if ( !upperAlgo->NeedDescretBoundary() ) + const std::vector< SMESH_subMesh * > & ancestors = GetAncestors(); + for ( size_t iA = 0; ( ret == SMESH_Hypothesis::HYP_OK && iA < ancestors.size()); ++iA ) { + if ( SMESH_Algo* upperAlgo = ancestors[ iA ]->GetAlgo() ) + if ( !upperAlgo->NeedDiscreteBoundary() && !upperAlgo->SupportSubmeshes()) ret = SMESH_Hypothesis::HYP_HIDDEN_ALGO; } // is algo hiding? - if ( ret == SMESH_Hypothesis::HYP_OK && !algo->NeedDescretBoundary() ) { + if ( ret == SMESH_Hypothesis::HYP_OK && + !algo->NeedDiscreteBoundary() && + !algo->SupportSubmeshes()) + { + TopoDS_Shape algoAssignedTo, otherAssignedTo; + gen->GetAlgo( this, &algoAssignedTo ); map::reverse_iterator i_sm = _mapDepend.rbegin(); for ( ; ( ret == SMESH_Hypothesis::HYP_OK && i_sm != _mapDepend.rend()) ; ++i_sm ) - if ( gen->GetAlgo( *_father, i_sm->second->_subShape )) + if ( gen->GetAlgo( i_sm->second, &otherAssignedTo ) && + SMESH_MesherHelper::IsSubShape( /*sub=*/otherAssignedTo, /*main=*/algoAssignedTo )) ret = SMESH_Hypothesis::HYP_HIDING_ALGO; } } + if ( _algo ) { // get an error description set by _algo->CheckHypothesis() + _computeError = _algo->GetComputeError(); + _algo->InitComputeError(); + } + bool stateChange = ( _algoState != oldAlgoState ); if ( stateChange && _algoState == HYP_OK ) // hyp becomes OK algo->SetEventListener( this ); - NotifyListenersOnEvent( event, ALGO_EVENT, anHyp ); + if ( event == REMOVE_ALGO || event == REMOVE_FATHER_ALGO ) + _algo = 0; + + notifyListenersOnEvent( event, ALGO_EVENT, anHyp ); if ( stateChange && oldAlgoState == HYP_OK ) { // hyp becomes KO - DeleteOwnListeners(); + deleteOwnListeners(); SetIsAlwaysComputed( false ); if (_subShape.ShapeType() == TopAbs_VERTEX ) { // restore default states @@ -1011,8 +1046,17 @@ SMESH_Hypothesis::Hypothesis_Status } } - if (stateChange || modifiedHyp) - ComputeStateEngine(MODIF_ALGO_STATE); + if ( algoRequiringCleaning ) { + // added or removed algo is all-dimensional + ComputeStateEngine( CLEAN ); + cleanDependsOn( algoRequiringCleaning ); + ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE ); + } + + if ( stateChange || modifiedHyp ) + ComputeStateEngine( MODIF_ALGO_STATE ); + + _realComputeCost = ( _algoState == HYP_OK ) ? computeCost() : 0; return ret; } @@ -1028,16 +1072,14 @@ bool SMESH_subMesh::IsConform(const SMESH_Algo* theAlgo) if ( !theAlgo ) return false; // Suppose that theAlgo is applicable to _subShape, do not check it here - //if ( !IsApplicableHypotesis( theAlgo )) return false; + //if ( !IsApplicableHypothesis( theAlgo )) return false; - // check only algo that doesn't NeedDescretBoundary(): because mesh made + // check only algo that doesn't NeedDiscreteBoundary(): because mesh made // on a sub-shape will be ignored by theAlgo - if ( theAlgo->NeedDescretBoundary() || + if ( theAlgo->NeedDiscreteBoundary() || !theAlgo->OnlyUnaryInput() ) // all adjacent shapes will be meshed by this algo? return true; - SMESH_Gen* gen =_father->GetGen(); - // only local algo is to be checked //if ( gen->IsGlobalHypothesis( theAlgo, *_father )) if ( _subShape.ShapeType() == _father->GetMeshDS()->ShapeToMesh().ShapeType() ) @@ -1050,18 +1092,18 @@ bool SMESH_subMesh::IsConform(const SMESH_Algo* theAlgo) for (; itsub.More(); itsub.Next()) { // loop on adjacent subShapes - TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( itsub.Value() )); - for (; it.More(); it.Next()) + const std::vector< SMESH_subMesh * > & ancestors = GetAncestors(); + for ( size_t iA = 0; iA < ancestors.size(); ++iA ) { - const TopoDS_Shape& adjacent = it.Value(); + const TopoDS_Shape& adjacent = ancestors[ iA ]->GetSubShape(); if ( _subShape.IsSame( adjacent )) continue; if ( adjacent.ShapeType() != _subShape.ShapeType()) break; // check algo attached to smAdjacent - SMESH_Algo * algo = gen->GetAlgo((*_father), adjacent); + SMESH_Algo * algo = ancestors[ iA ]->GetAlgo(); if (algo && - !algo->NeedDescretBoundary() && + !algo->NeedDiscreteBoundary() && algo->OnlyUnaryInput()) return false; // NOT CONFORM MESH WILL BE PRODUCED } @@ -1076,19 +1118,29 @@ bool SMESH_subMesh::IsConform(const SMESH_Algo* theAlgo) */ //============================================================================= -void SMESH_subMesh::SetAlgoState(int state) +void SMESH_subMesh::setAlgoState(algo_state state) { _algoState = state; } -//============================================================================= +//================================================================================ /*! + * \brief Send an event to sub-meshes + * \param [in] event - the event + * \param [in] anHyp - an hypothesis + * \param [in] exitOnFatal - to stop iteration on sub-meshes if a sub-mesh + * reports a fatal result + * \return SMESH_Hypothesis::Hypothesis_Status - the worst result * + * Optional description of a problematic situation (if any) can be retrieved + * via GetComputeError(). */ -//============================================================================= +//================================================================================ + SMESH_Hypothesis::Hypothesis_Status - SMESH_subMesh::SubMeshesAlgoStateEngine(int event, - SMESH_Hypothesis * anHyp) + SMESH_subMesh::SubMeshesAlgoStateEngine(algo_event event, + SMESH_Hypothesis * anHyp, + bool exitOnFatal) { SMESH_Hypothesis::Hypothesis_Status ret = SMESH_Hypothesis::HYP_OK; //EAP: a wire (dim==1) should notify edges (dim==1) @@ -1097,80 +1149,135 @@ SMESH_Hypothesis::Hypothesis_Status { SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false); while ( smIt->more() ) { - SMESH_Hypothesis::Hypothesis_Status ret2 = - smIt->next()->AlgoStateEngine(event, anHyp); + SMESH_subMesh* sm = smIt->next(); + SMESH_Hypothesis::Hypothesis_Status ret2 = sm->AlgoStateEngine(event, anHyp); if ( ret2 > ret ) + { ret = ret2; + _computeError = sm->_computeError; + sm->_computeError.reset(); + if ( exitOnFatal && SMESH_Hypothesis::IsStatusFatal( ret )) + break; + } } } return ret; } -//============================================================================= -/*! - * - */ -//============================================================================= - -void SMESH_subMesh::CleanDependsOn() -{ - SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false); - while ( smIt->more() ) - smIt->next()->ComputeStateEngine(CLEAN); -} - -//============================================================================= +//================================================================================ /*! - * + * \brief Remove elements from sub-meshes. + * \param algoRequiringCleaning - an all-dimensional algorithm whose presence + * causes the cleaning. */ -//============================================================================= +//================================================================================ -void SMESH_subMesh::DumpAlgoState(bool isMain) +void SMESH_subMesh::cleanDependsOn( SMESH_Algo* algoRequiringCleaning/*=0*/ ) { - int dim = SMESH_Gen::GetShapeDim(_subShape); -// if (dim < 1) return; - if (isMain) - { - const map < int, SMESH_subMesh * >&subMeshes = DependsOn(); - - map < int, SMESH_subMesh * >::const_iterator itsub; - for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++) - { - SMESH_subMesh *sm = (*itsub).second; - sm->DumpAlgoState(false); - } - } - int type = _subShape.ShapeType(); - MESSAGE("dim = " << dim << " type of shape " << type); - switch (_algoState) - { - case NO_ALGO: - MESSAGE(" AlgoState = NO_ALGO"); - break; - case MISSING_HYP: - MESSAGE(" AlgoState = MISSING_HYP"); - break; - case HYP_OK: - MESSAGE(" AlgoState = HYP_OK"); - break; - } - switch (_computeState) - { - case NOT_READY: - MESSAGE(" ComputeState = NOT_READY"); - break; - case READY_TO_COMPUTE: - MESSAGE(" ComputeState = READY_TO_COMPUTE"); - break; - case COMPUTE_OK: - MESSAGE(" ComputeState = COMPUTE_OK"); - break; - case FAILED_TO_COMPUTE: - MESSAGE(" ComputeState = FAILED_TO_COMPUTE"); - break; - } -} - + SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false, + /*complexShapeFirst=*/true); + if ( _father->NbNodes() == 0 ) + { + while ( smIt->more() ) + smIt->next()->ComputeStateEngine(CHECK_COMPUTE_STATE); + } + else if ( !algoRequiringCleaning || !algoRequiringCleaning->SupportSubmeshes() ) + { + while ( smIt->more() ) + smIt->next()->ComputeStateEngine(CLEAN); + } + else if ( algoRequiringCleaning && algoRequiringCleaning->SupportSubmeshes() ) + { + // find sub-meshes to keep elements on + set< SMESH_subMesh* > smToKeep; + TopAbs_ShapeEnum prevShapeType = TopAbs_SHAPE; + bool toKeepPrevShapeType = false; + while ( smIt->more() ) + { + SMESH_subMesh* sm = smIt->next(); + sm->ComputeStateEngine(CHECK_COMPUTE_STATE); + if ( !sm->IsEmpty() ) + { + const bool sameShapeType = ( prevShapeType == sm->GetSubShape().ShapeType() ); + bool keepSubMeshes = ( sameShapeType && toKeepPrevShapeType ); + if ( !sameShapeType ) + { + // check if the algo allows presence of global algos of dimension the algo + // can generate it-self; + // always keep a node on VERTEX, as this node can be shared by segments + // lying on EDGEs not shared by the VERTEX of sm, due to MergeNodes (PAL23068) + int shapeDim = SMESH_Gen::GetShapeDim( sm->GetSubShape() ); + keepSubMeshes = ( algoRequiringCleaning->NeedLowerHyps( shapeDim ) || shapeDim == 0 ); + prevShapeType = sm->GetSubShape().ShapeType(); + toKeepPrevShapeType = keepSubMeshes; + } + if ( !keepSubMeshes ) + { + // look for a local algo used to mesh sm + TopoDS_Shape algoShape = SMESH_MesherHelper::GetShapeOfHypothesis + ( algoRequiringCleaning, _subShape, _father ); + SMESH_HypoFilter moreLocalAlgo; + moreLocalAlgo.Init( SMESH_HypoFilter::IsMoreLocalThan( algoShape, *_father )); + moreLocalAlgo.And ( SMESH_HypoFilter::IsAlgo() ); + bool localAlgoFound = _father->GetHypothesis( sm->_subShape, moreLocalAlgo, true ); + keepSubMeshes = localAlgoFound; + } + // remember all sub-meshes of sm + if ( keepSubMeshes ) + { + SMESH_subMeshIteratorPtr smIt2 = sm->getDependsOnIterator(true); + while ( smIt2->more() ) + smToKeep.insert( smIt2->next() ); + } + } + } + // remove elements + SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,true); + while ( smIt->more() ) + { + SMESH_subMesh* sm = smIt->next(); + if ( !smToKeep.count( sm )) + sm->ComputeStateEngine(CLEAN); + } + } +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +void SMESH_subMesh::DumpAlgoState(bool isMain) +{ + if (isMain) + { + const map < int, SMESH_subMesh * >&subMeshes = DependsOn(); + + map < int, SMESH_subMesh * >::const_iterator itsub; + for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++) + { + SMESH_subMesh *sm = (*itsub).second; + sm->DumpAlgoState(false); + } + } + MESSAGE("dim = " << SMESH_Gen::GetShapeDim(_subShape) << + " type of shape " << _subShape.ShapeType()); + switch (_algoState) + { + case NO_ALGO : MESSAGE(" AlgoState = NO_ALGO"); break; + case MISSING_HYP : MESSAGE(" AlgoState = MISSING_HYP"); break; + case HYP_OK : MESSAGE(" AlgoState = HYP_OK");break; + } + switch (_computeState) + { + case NOT_READY : MESSAGE(" ComputeState = NOT_READY");break; + case READY_TO_COMPUTE : MESSAGE(" ComputeState = READY_TO_COMPUTE");break; + case COMPUTE_OK : MESSAGE(" ComputeState = COMPUTE_OK");break; + case FAILED_TO_COMPUTE: MESSAGE(" ComputeState = FAILED_TO_COMPUTE");break; + } +} + //================================================================================ /*! * \brief Remove nodes and elements bound to submesh @@ -1181,25 +1288,25 @@ void SMESH_subMesh::DumpAlgoState(bool isMain) static void cleanSubMesh( SMESH_subMesh * subMesh ) { if (subMesh) { - if (SMESHDS_SubMesh * subMeshDS = subMesh->GetSubMeshDS()) { + if (SMESHDS_SubMesh * subMeshDS = subMesh->GetSubMeshDS()) + { SMESHDS_Mesh * meshDS = subMesh->GetFather()->GetMeshDS(); - SMDS_ElemIteratorPtr ite = subMeshDS->GetElements(); - while (ite->more()) { - const SMDS_MeshElement * elt = ite->next(); - //MESSAGE( " RM elt: "<GetID()<<" ( "<NbNodes()<<" )" ); - //meshDS->RemoveElement(elt); - meshDS->RemoveFreeElement(elt, subMeshDS); - } - - SMDS_NodeIteratorPtr itn = subMeshDS->GetNodes(); - while (itn->more()) { - const SMDS_MeshNode * node = itn->next(); - //MESSAGE( " RM node: "<GetID()); - if ( node->NbInverseNodes() == 0 ) - meshDS->RemoveFreeNode(node, subMeshDS); - else // for StdMeshers_CompositeSegment_1D: node in one submesh, edge in another - meshDS->RemoveNode(node); - } + int nbElems = subMeshDS->NbElements(); + if ( nbElems > 0 ) + for ( SMDS_ElemIteratorPtr ite = subMeshDS->GetElements(); ite->more(); ) + meshDS->RemoveFreeElement( ite->next(), subMeshDS ); + + int nbNodes = subMeshDS->NbNodes(); + if ( nbNodes > 0 ) + for ( SMDS_NodeIteratorPtr itn = subMeshDS->GetNodes(); itn->more() ; ) + { + const SMDS_MeshNode * node = itn->next(); + if ( node->NbInverseElements() == 0 ) + meshDS->RemoveFreeNode( node, subMeshDS ); + else // for StdMeshers_CompositeSegment_1D: node in one submesh, edge in another + meshDS->RemoveNode( node ); + } + subMeshDS->Clear(); } } } @@ -1210,22 +1317,42 @@ static void cleanSubMesh( SMESH_subMesh * subMesh ) */ //============================================================================= -bool SMESH_subMesh::ComputeStateEngine(int event) +bool SMESH_subMesh::ComputeStateEngine(compute_event event) { - _computeError.reset(); + switch ( event ) { + case MODIF_ALGO_STATE: + case COMPUTE: + case COMPUTE_SUBMESH: + //case COMPUTE_CANCELED: + case CLEAN: + //case SUBMESH_COMPUTED: + //case SUBMESH_RESTORED: + //case SUBMESH_LOADED: + //case MESH_ENTITY_REMOVED: + //case CHECK_COMPUTE_STATE: + _computeError.reset(); break; + default:; + } - //MESSAGE("SMESH_subMesh::ComputeStateEngine"); - //SCRUTE(_computeState); - //SCRUTE(event); + if ( event == CLEAN ) + _alwaysComputed = false; // Unset 'true' set by MergeNodes() (issue 0022182) if (_subShape.ShapeType() == TopAbs_VERTEX) { _computeState = READY_TO_COMPUTE; SMESHDS_SubMesh* smDS = GetSubMeshDS(); - if ( smDS && smDS->NbNodes() ) { - _computeState = COMPUTE_OK; + if ( smDS && smDS->NbNodes() ) + { + if ( event == CLEAN ) { + cleanDependants(); + cleanSubMesh( this ); + } + else + _computeState = COMPUTE_OK; } - else if ( event == COMPUTE && !_alwaysComputed ) { + else if (( event == COMPUTE || event == COMPUTE_SUBMESH ) + && !_alwaysComputed ) + { const TopoDS_Vertex & V = TopoDS::Vertex( _subShape ); gp_Pnt P = BRep_Tool::Pnt(V); if ( SMDS_MeshNode * n = _father->GetMeshDS()->AddNode(P.X(), P.Y(), P.Z()) ) { @@ -1234,7 +1361,7 @@ bool SMESH_subMesh::ComputeStateEngine(int event) } } if ( event == MODIF_ALGO_STATE ) - CleanDependants(); + cleanDependants(); return true; } SMESH_Gen *gen = _father->GetGen(); @@ -1252,25 +1379,32 @@ bool SMESH_subMesh::ComputeStateEngine(int event) switch (event) { case MODIF_ALGO_STATE: - algo = gen->GetAlgo((*_father), _subShape); - if (algo && !algo->NeedDescretBoundary()) - CleanDependsOn(); // clean sub-meshes with event CLEAN + algo = GetAlgo(); + if (algo && !algo->NeedDiscreteBoundary()) + cleanDependsOn( algo ); // clean sub-meshes with event CLEAN if ( _algoState == HYP_OK ) _computeState = READY_TO_COMPUTE; break; - case COMPUTE: // nothing to do + case COMPUTE: // nothing to do + case COMPUTE_SUBMESH: + break; + case COMPUTE_CANCELED: // nothing to do break; case CLEAN: - CleanDependants(); - RemoveSubMeshElementsAndNodes(); + cleanDependants(); + removeSubMeshElementsAndNodes(); break; - case SUBMESH_COMPUTED: // nothing to do + case SUBMESH_COMPUTED: // nothing to do break; case SUBMESH_RESTORED: ComputeSubMeshStateEngine( SUBMESH_RESTORED ); break; case MESH_ENTITY_REMOVED: break; + case SUBMESH_LOADED: + loadDependentMeshes(); + ComputeSubMeshStateEngine( SUBMESH_LOADED ); + //break; case CHECK_COMPUTE_STATE: if ( IsMeshComputed() ) _computeState = COMPUTE_OK; @@ -1288,55 +1422,100 @@ bool SMESH_subMesh::ComputeStateEngine(int event) { case MODIF_ALGO_STATE: _computeState = NOT_READY; - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); if (algo) { - if (!algo->NeedDescretBoundary()) - CleanDependsOn(); // clean sub-meshes with event CLEAN + if (!algo->NeedDiscreteBoundary()) + cleanDependsOn( algo ); // clean sub-meshes with event CLEAN if ( _algoState == HYP_OK ) _computeState = READY_TO_COMPUTE; } break; + + case COMPUTE_NOGEOM: // no geometry; can be several algos + if ( !_father->HasShapeToMesh() ) + { + algo = GetAlgo(); // current algo + if ( algo ) + { + // apply algos in the order of increasing dimension + std::list< const SMESHDS_Hypothesis * > algos = _father->GetHypothesisList( _subShape ); + for ( int t = SMESHDS_Hypothesis::ALGO_1D; t <= SMESHDS_Hypothesis::ALGO_3D; ++t ) + { + std::list::iterator al = algos.begin(); + for ( ; al != algos.end(); ++al ) + if ( (*al)->GetType() == t ) + { + _algo = (SMESH_Algo*) *al; + _computeState = READY_TO_COMPUTE; + if ( !ComputeStateEngine( COMPUTE )) + break; + } + } + _algo = algo; // restore + } + break; + } case COMPUTE: + case COMPUTE_SUBMESH: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); ret = algo->CheckHypothesis((*_father), _subShape, hyp_status); if (!ret) { MESSAGE("***** verify compute state *****"); _computeState = NOT_READY; - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); break; } + TopoDS_Shape shape = _subShape; + algo->SubMeshesToCompute().assign( 1, this ); // check submeshes needed if (_father->HasShapeToMesh() ) { - bool subComputed = SubMeshesComputed(); - ret = ( algo->NeedDescretBoundary() ? subComputed : + 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 ); + } + else { + subComputed = SubMeshesComputed(); + } + ret = ( algo->NeedDiscreteBoundary() ? subComputed : + algo->SupportSubmeshes() ? !subFailed : ( !subComputed || _father->IsNotConformAllowed() )); - if (!ret) { + if (!ret) + { _computeState = FAILED_TO_COMPUTE; - if ( !algo->NeedDescretBoundary() ) + if ( !algo->NeedDiscreteBoundary() && !subFailed ) _computeError = SMESH_ComputeError::New(COMPERR_BAD_INPUT_MESH, - "Unexpected computed submesh",algo); - break; + "Unexpected computed sub-mesh",algo); + break; // goto exit } } - // compute -// CleanDependants(); for "UseExisting_*D" algos -// RemoveSubMeshElementsAndNodes(); + // Compute + + // to restore cout that may be redirected by algo + std::streambuf* coutBuffer = std::cout.rdbuf(); + + //cleanDependants(); for "UseExisting_*D" algos + //removeSubMeshElementsAndNodes(); + loadDependentMeshes(); ret = false; _computeState = FAILED_TO_COMPUTE; _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo); - TopoDS_Shape shape = _subShape; try { -#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100 OCC_CATCH_SIGNALS; -#endif + algo->InitComputeError(); + MemoryReserve aMemoryReserve; SMDS_Mesh::CheckMemory(); + Kernel_Utils::Localizer loc; if ( !_father->HasShapeToMesh() ) // no shape { SMESH_MesherHelper helper( *_father ); @@ -1346,28 +1525,28 @@ bool SMESH_subMesh::ComputeStateEngine(int event) } else { - if (!algo->OnlyUnaryInput()) { - shape = GetCollection( gen, algo ); - } ret = algo->Compute((*_father), shape); } - if ( !ret ) - _computeError = algo->GetComputeError(); + // algo can set _computeError of submesh + _computeError = SMESH_ComputeError::Worst( _computeError, algo->GetComputeError() ); + } + catch ( ::SMESH_ComputeError& comperr ) { + cout << " SMESH_ComputeError caught" << endl; + if ( !_computeError ) _computeError = SMESH_ComputeError::New(); + *_computeError = comperr; } catch ( std::bad_alloc& exc ) { - printf("std::bad_alloc thrown inside algo->Compute()\n"); + MESSAGE("std::bad_alloc thrown inside algo->Compute()"); if ( _computeError ) { _computeError->myName = COMPERR_MEMORY_PB; - //_computeError->myComment = exc.what(); } cleanSubMesh( this ); throw exc; } catch ( Standard_OutOfMemory& exc ) { - printf("Standard_OutOfMemory thrown inside algo->Compute()\n"); + MESSAGE("Standard_OutOfMemory thrown inside algo->Compute()"); if ( _computeError ) { _computeError->myName = COMPERR_MEMORY_PB; - //_computeError->myComment = exc.what(); } cleanSubMesh( this ); throw std::bad_alloc(); @@ -1382,9 +1561,12 @@ bool SMESH_subMesh::ComputeStateEngine(int event) } } catch ( SALOME_Exception& S_ex ) { + const int skipSalomeShift = 7; /* to skip "Salome " of + "Salome Exception" prefix returned + by SALOME_Exception::what() */ if ( !_computeError ) _computeError = SMESH_ComputeError::New(); _computeError->myName = COMPERR_SLM_EXCEPTION; - _computeError->myComment = S_ex.what(); + _computeError->myComment = S_ex.what() + skipSalomeShift; } catch ( std::exception& exc ) { if ( !_computeError ) _computeError = SMESH_ComputeError::New(); @@ -1397,38 +1579,126 @@ bool SMESH_subMesh::ComputeStateEngine(int event) else ret = false; } - if (ret && !_alwaysComputed) { // check if anything was built - ret = ( GetSubMeshDS() && ( GetSubMeshDS()->NbElements() || GetSubMeshDS()->NbNodes() )); + std::cout.rdbuf( coutBuffer ); // restore cout that could be redirected by algo + + // check if an error reported on any sub-shape + bool isComputeErrorSet = !checkComputeError( algo, ret, shape ); + if ( isComputeErrorSet ) + ret = false; + // check if anything was built + TopExp_Explorer subS(shape, _subShape.ShapeType()); + if ( ret ) + { + for (; ret && subS.More(); subS.Next()) + if ( !_father->GetSubMesh( subS.Current() )->IsMeshComputed() && + ( _subShape.ShapeType() != TopAbs_EDGE || + !algo->isDegenerated( TopoDS::Edge( subS.Current() )))) + ret = false; } - bool isComputeErrorSet = !CheckComputeError( algo, shape ); - if (!ret && !isComputeErrorSet) +#ifdef PRINT_WHO_COMPUTE_WHAT + for (subS.ReInit(); subS.More(); subS.Next()) { - // Set _computeError - if ( !_computeError ) - _computeError = SMESH_ComputeError::New(); - if ( _computeError->IsOK() ) - _computeError->myName = COMPERR_ALGO_FAILED; - _computeState = FAILED_TO_COMPUTE; + const std::list & hyps = + _algo->GetUsedHypothesis( *_father, _subShape ); + SMESH_Comment hypStr; + if ( !hyps.empty() ) + { + hypStr << hyps.front()->GetName() << " "; + ((SMESHDS_Hypothesis*)hyps.front())->SaveTo( hypStr.Stream() ); + hypStr << " "; + } + cout << _algo->GetName() + << " " << _father->GetSubMesh( subS.Current() )->GetId() + << " " << hypStr << endl; } - if (ret) +#endif + // Set _computeError + if ( !ret && !isComputeErrorSet ) + { + for ( subS.ReInit(); subS.More(); subS.Next() ) + { + SMESH_subMesh* sm = _father->GetSubMesh( subS.Current() ); + if ( !sm->IsMeshComputed() ) + { + if ( !sm->_computeError ) + sm->_computeError = SMESH_ComputeError::New(); + if ( sm->_computeError->IsOK() ) + sm->_computeError->myName = COMPERR_ALGO_FAILED; + sm->_computeState = FAILED_TO_COMPUTE; + sm->_computeError->myAlgo = algo; + } + } + } + if ( ret && _computeError && _computeError->myName != COMPERR_WARNING ) { _computeError.reset(); } - UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED + + // transform errors into warnings if it is caused by mesh edition (imp 0023068) + if (!ret && _father->GetIsModified() ) + { + for (subS.ReInit(); subS.More(); subS.Next()) + { + SMESH_subMesh* sm = _father->GetSubMesh( subS.Current() ); + if ( !sm->IsMeshComputed() && sm->_computeError ) + { + // check if there is a VERTEX w/o nodes + // with READY_TO_COMPUTE state (after MergeNodes()) + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(false,false); + while ( smIt->more() ) + { + SMESH_subMesh * vertSM = smIt->next(); + if ( vertSM->_subShape.ShapeType() != TopAbs_VERTEX ) break; + if ( vertSM->GetComputeState() == READY_TO_COMPUTE ) + { + SMESHDS_SubMesh * ds = vertSM->GetSubMeshDS(); + if ( !ds || ds->NbNodes() == 0 ) + { + sm->_computeState = READY_TO_COMPUTE; + sm->_computeError->myName = COMPERR_WARNING; + break; + } + } + } + } + } + } + + // send event SUBMESH_COMPUTED + if ( ret ) { + if ( !algo->NeedDiscreteBoundary() ) + // send SUBMESH_COMPUTED to dependants of all sub-meshes of shape + for (subS.ReInit(); subS.More(); subS.Next()) + { + SMESH_subMesh* sm = _father->GetSubMesh( subS.Current() ); + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(false,false); + while ( smIt->more() ) { + sm = smIt->next(); + if ( sm->GetSubShape().ShapeType() == TopAbs_VERTEX ) + sm->updateDependantsState( SUBMESH_COMPUTED ); + else + break; + } + } + else + updateDependantsState( SUBMESH_COMPUTED ); + } } break; + case COMPUTE_CANCELED: // nothing to do + break; case CLEAN: - CleanDependants(); - RemoveSubMeshElementsAndNodes(); + cleanDependants(); + removeSubMeshElementsAndNodes(); _computeState = NOT_READY; - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); if (algo) { ret = algo->CheckHypothesis((*_father), _subShape, hyp_status); if (ret) _computeState = READY_TO_COMPUTE; else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; case SUBMESH_COMPUTED: // nothing to do @@ -1438,14 +1708,20 @@ bool SMESH_subMesh::ComputeStateEngine(int event) // happen after retrieval from a file ComputeStateEngine( CHECK_COMPUTE_STATE ); ComputeSubMeshStateEngine( SUBMESH_RESTORED ); - algo = gen->GetAlgo(*_father, _subShape); + algo = GetAlgo(); if (algo) algo->SubmeshRestored( this ); break; case MESH_ENTITY_REMOVED: break; + case SUBMESH_LOADED: + loadDependentMeshes(); + ComputeSubMeshStateEngine( SUBMESH_LOADED ); + //break; case CHECK_COMPUTE_STATE: if ( IsMeshComputed() ) _computeState = COMPUTE_OK; + else if ( _computeError && _computeError->IsKO() ) + _computeState = FAILED_TO_COMPUTE; break; default: ASSERT(0); @@ -1460,15 +1736,17 @@ bool SMESH_subMesh::ComputeStateEngine(int event) { case MODIF_ALGO_STATE: ComputeStateEngine( CLEAN ); - algo = gen->GetAlgo((*_father), _subShape); - if (algo && !algo->NeedDescretBoundary()) - CleanDependsOn(); // clean sub-meshes with event CLEAN + algo = GetAlgo(); + if (algo && !algo->NeedDiscreteBoundary()) + cleanDependsOn( algo ); // clean sub-meshes with event CLEAN break; case COMPUTE: // nothing to do break; + case COMPUTE_CANCELED: // nothing to do + break; case CLEAN: - CleanDependants(); // clean sub-meshes, dependant on this one, with event CLEAN - RemoveSubMeshElementsAndNodes(); + cleanDependants(); // clean sub-meshes, dependent on this one, with event CLEAN + removeSubMeshElementsAndNodes(); _computeState = NOT_READY; if ( _algoState == HYP_OK ) _computeState = READY_TO_COMPUTE; @@ -1478,20 +1756,24 @@ bool SMESH_subMesh::ComputeStateEngine(int event) case SUBMESH_RESTORED: ComputeStateEngine( CHECK_COMPUTE_STATE ); ComputeSubMeshStateEngine( SUBMESH_RESTORED ); - algo = gen->GetAlgo(*_father, _subShape); + algo = GetAlgo(); if (algo) algo->SubmeshRestored( this ); break; case MESH_ENTITY_REMOVED: - UpdateDependantsState( CHECK_COMPUTE_STATE ); - ComputeStateEngine( CHECK_COMPUTE_STATE ); + updateDependantsState ( CHECK_COMPUTE_STATE ); + ComputeStateEngine ( CHECK_COMPUTE_STATE ); ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE ); break; case CHECK_COMPUTE_STATE: - if ( !IsMeshComputed() ) + if ( !IsMeshComputed() ) { if (_algoState == HYP_OK) _computeState = READY_TO_COMPUTE; else _computeState = NOT_READY; + } + break; + case SUBMESH_LOADED: + // already treated event, thanks to which _computeState == COMPUTE_OK break; default: ASSERT(0); @@ -1505,22 +1787,37 @@ bool SMESH_subMesh::ComputeStateEngine(int event) switch (event) { case MODIF_ALGO_STATE: + if ( !IsEmpty() ) + ComputeStateEngine( CLEAN ); + algo = GetAlgo(); + if (algo && !algo->NeedDiscreteBoundary()) + cleanDependsOn( algo ); // clean sub-meshes with event CLEAN if (_algoState == HYP_OK) _computeState = READY_TO_COMPUTE; else _computeState = NOT_READY; break; - case COMPUTE: // nothing to do + case COMPUTE: // nothing to do + case COMPUTE_SUBMESH: + break; + case COMPUTE_CANCELED: + { + algo = GetAlgo(); + algo->CancelCompute(); + } break; case CLEAN: - CleanDependants(); // submeshes dependent on me should be cleaned as well - RemoveSubMeshElementsAndNodes(); + cleanDependants(); // submeshes dependent on me should be cleaned as well + removeSubMeshElementsAndNodes(); break; case SUBMESH_COMPUTED: // allow retry compute - if (_algoState == HYP_OK) - _computeState = READY_TO_COMPUTE; - else - _computeState = NOT_READY; + if ( IsEmpty() ) // 23061 + { + if (_algoState == HYP_OK) + _computeState = READY_TO_COMPUTE; + else + _computeState = NOT_READY; + } break; case SUBMESH_RESTORED: ComputeSubMeshStateEngine( SUBMESH_RESTORED ); @@ -1536,6 +1833,8 @@ bool SMESH_subMesh::ComputeStateEngine(int event) else _computeState = NOT_READY; break; + // case SUBMESH_LOADED: + // break; default: ASSERT(0); break; @@ -1548,11 +1847,83 @@ bool SMESH_subMesh::ComputeStateEngine(int event) break; } - NotifyListenersOnEvent( event, COMPUTE_EVENT ); + notifyListenersOnEvent( event, COMPUTE_EVENT ); + + return ret; +} + + +//============================================================================= +/*! + * + */ +//============================================================================= + +bool SMESH_subMesh::Evaluate(MapShapeNbElems& aResMap) +{ + _computeError.reset(); + + bool ret = true; + + if (_subShape.ShapeType() == TopAbs_VERTEX) { + vector aVec(SMDSEntity_Last,0); + aVec[SMDSEntity_Node] = 1; + aResMap.insert(make_pair(this,aVec)); + return ret; + } + + //SMESH_Gen *gen = _father->GetGen(); + SMESH_Algo *algo = 0; + SMESH_Hypothesis::Hypothesis_Status hyp_status; + + algo = GetAlgo(); + if( algo && !aResMap.count( this )) + { + ret = algo->CheckHypothesis((*_father), _subShape, hyp_status); + if (!ret) return false; + + if (_father->HasShapeToMesh() && algo->NeedDiscreteBoundary() ) + { + // check submeshes needed + bool subMeshEvaluated = true; + int dimToCheck = SMESH_Gen::GetShapeDim( _subShape ) - 1; + SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,/*complexShapeFirst=*/true); + while ( smIt->more() && subMeshEvaluated ) + { + SMESH_subMesh* sm = smIt->next(); + int dim = SMESH_Gen::GetShapeDim( sm->GetSubShape() ); + if (dim < dimToCheck) break; // the rest subMeshes are all of less dimension + const vector & nbs = aResMap[ sm ]; + subMeshEvaluated = (std::accumulate( nbs.begin(), nbs.end(), 0 ) > 0 ); + } + if ( !subMeshEvaluated ) + return false; + } + _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo); + + if ( IsMeshComputed() ) + { + vector & nbEntities = aResMap[ this ]; + nbEntities.resize( SMDSEntity_Last, 0 ); + if ( SMESHDS_SubMesh* sm = GetSubMeshDS() ) + { + nbEntities[ SMDSEntity_Node ] = sm->NbNodes(); + SMDS_ElemIteratorPtr elemIt = sm->GetElements(); + while ( elemIt->more() ) + nbEntities[ elemIt->next()->GetEntityType() ]++; + } + } + else + { + ret = algo->Evaluate((*_father), _subShape, aResMap); + } + aResMap.insert( make_pair( this,vector(0))); + } return ret; } + //======================================================================= /*! * \brief Update compute_state by _computeError and send proper events to @@ -1561,18 +1932,20 @@ bool SMESH_subMesh::ComputeStateEngine(int event) */ //======================================================================= -bool SMESH_subMesh::CheckComputeError(SMESH_Algo* theAlgo, const TopoDS_Shape& theShape) +bool SMESH_subMesh::checkComputeError(SMESH_Algo* theAlgo, + const bool theComputeOK, + const TopoDS_Shape& theShape) { bool noErrors = true; if ( !theShape.IsNull() ) { // Check state of submeshes - if ( !theAlgo->NeedDescretBoundary()) + if ( !theAlgo->NeedDiscreteBoundary()) { SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false); while ( smIt->more() ) - if ( !smIt->next()->CheckComputeError( theAlgo )) + if ( !smIt->next()->checkComputeError( theAlgo, theComputeOK )) noErrors = false; } @@ -1584,27 +1957,39 @@ bool SMESH_subMesh::CheckComputeError(SMESH_Algo* theAlgo, const TopoDS_Shape& t for (TopoDS_Iterator subIt( theShape ); subIt.More(); subIt.Next()) { SMESH_subMesh* sm = _father->GetSubMesh( subIt.Value() ); if ( sm != this ) { - if ( !sm->CheckComputeError( theAlgo )) + if ( !sm->checkComputeError( theAlgo, theComputeOK, sm->GetSubShape() )) noErrors = false; - UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED + updateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED } } } } { - // Check my state + + // Set my _computeState + if ( !_computeError || _computeError->IsOK() ) { - _computeState = COMPUTE_OK; + // no error description is set to this sub-mesh, check if any mesh is computed + _computeState = IsMeshComputed() ? COMPUTE_OK : FAILED_TO_COMPUTE; + if ( _computeState != COMPUTE_OK ) + { + if ( _subShape.ShapeType() == TopAbs_EDGE && + SMESH_Algo::isDegenerated( TopoDS::Edge( _subShape )) ) + _computeState = COMPUTE_OK; + else if ( theComputeOK ) + _computeError = SMESH_ComputeError::New(COMPERR_NO_MESH_ON_SHAPE,"",theAlgo); + } } - else + + if ( _computeError && !_computeError->IsOK() ) { if ( !_computeError->myAlgo ) _computeError->myAlgo = theAlgo; // Show error SMESH_Comment text; - text << theAlgo->GetName() << " failed on subshape #" << _Id << " with error "; + text << theAlgo->GetName() << " failed on sub-shape #" << _Id << " with error "; if (_computeError->IsCommon() ) text << _computeError->CommonName(); else @@ -1612,73 +1997,22 @@ bool SMESH_subMesh::CheckComputeError(SMESH_Algo* theAlgo, const TopoDS_Shape& t if ( _computeError->myComment.size() > 0 ) text << " \"" << _computeError->myComment << "\""; -#ifdef _DEBUG_ - cout << text << endl; - // Show vertices location of a failed shape - TopTools_IndexedMapOfShape vMap; - TopExp::MapShapes( _subShape, TopAbs_VERTEX, vMap ); - cout << "Subshape vertices " << ( vMap.Extent()>10 ? "(first 10):" : ":") << endl; - for ( int iv = 1; iv <= vMap.Extent() && iv < 11; ++iv ) { - gp_Pnt P( BRep_Tool::Pnt( TopoDS::Vertex( vMap( iv ) ))); - cout << "#" << _father->GetMeshDS()->ShapeToIndex( vMap( iv )) << " "; - cout << P.X() << " " << P.Y() << " " << P.Z() << " " << endl; - } -#else INFOS( text ); -#endif - _computeState = FAILED_TO_COMPUTE; - noErrors = false; - } - } - return noErrors; -} - -//======================================================================= -//function : ApplyToCollection -//purpose : Apply theAlgo to all subshapes in theCollection -//======================================================================= - -bool SMESH_subMesh::ApplyToCollection (SMESH_Algo* theAlgo, - const TopoDS_Shape& theCollection) -{ - MESSAGE("SMESH_subMesh::ApplyToCollection"); - ASSERT ( !theAlgo->NeedDescretBoundary() ); - if ( _computeError ) - _computeError->myName = COMPERR_OK; + _computeState = _computeError->IsKO() ? FAILED_TO_COMPUTE : COMPUTE_OK; - bool ok = theAlgo->Compute( *_father, theCollection ); - - // set _computeState of subshapes - TopExp_Explorer anExplorer( theCollection, _subShape.ShapeType() ); - for ( ; anExplorer.More(); anExplorer.Next() ) - { - if ( SMESH_subMesh* subMesh = _father->GetSubMeshContaining( anExplorer.Current() )) - { - bool localOK = subMesh->CheckComputeError( theAlgo ); - if ( !ok && localOK && !subMesh->IsMeshComputed() ) - { - subMesh->_computeError = theAlgo->GetComputeError(); - if ( subMesh->_computeError->IsOK() ) - _computeError = SMESH_ComputeError::New(COMPERR_ALGO_FAILED); - localOK = CheckComputeError( theAlgo ); - } - if ( localOK ) - subMesh->UpdateDependantsState( SUBMESH_COMPUTED ); - subMesh->UpdateSubMeshState( localOK ? COMPUTE_OK : FAILED_TO_COMPUTE ); + noErrors = false; } } - - return true; + return noErrors; } - //======================================================================= -//function : UpdateSubMeshState +//function : updateSubMeshState //purpose : //======================================================================= -void SMESH_subMesh::UpdateSubMeshState(const compute_state theState) +void SMESH_subMesh::updateSubMeshState(const compute_state theState) { SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false); while ( smIt->more() ) @@ -1690,68 +2024,58 @@ void SMESH_subMesh::UpdateSubMeshState(const compute_state theState) //purpose : //======================================================================= -void SMESH_subMesh::ComputeSubMeshStateEngine(int event) +void SMESH_subMesh::ComputeSubMeshStateEngine(compute_event event, const bool includeSelf) { - SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false); + SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(includeSelf,false); while ( smIt->more() ) smIt->next()->ComputeStateEngine(event); } //======================================================================= -//function : UpdateDependantsState +//function : updateDependantsState //purpose : //======================================================================= -void SMESH_subMesh::UpdateDependantsState(const compute_event theEvent) +void SMESH_subMesh::updateDependantsState(const compute_event theEvent) { - //MESSAGE("SMESH_subMesh::UpdateDependantsState"); - TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape )); - for (; it.More(); it.Next()) + const std::vector< SMESH_subMesh * > & ancestors = GetAncestors(); + for ( size_t iA = 0; iA < ancestors.size(); ++iA ) { - const TopoDS_Shape& ancestor = it.Value(); - SMESH_subMesh *aSubMesh = - _father->GetSubMeshContaining(ancestor); - if (aSubMesh) - aSubMesh->ComputeStateEngine( theEvent ); + ancestors[ iA ]->ComputeStateEngine( theEvent ); } } -//============================================================================= -/*! - * - */ -//============================================================================= +//======================================================================= +//function : cleanDependants +//purpose : +//======================================================================= -void SMESH_subMesh::CleanDependants() +void SMESH_subMesh::cleanDependants() { int dimToClean = SMESH_Gen::GetShapeDim( _subShape ) + 1; - TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape )); - for (; it.More(); it.Next()) + const std::vector< SMESH_subMesh * > & ancestors = GetAncestors(); + for ( size_t iA = 0; iA < ancestors.size(); ++iA ) { - const TopoDS_Shape& ancestor = it.Value(); - if ( SMESH_Gen::GetShapeDim( ancestor ) == dimToClean ) { + const TopoDS_Shape& ancestor = ancestors[ iA ]->GetSubShape(); + if ( SMESH_Gen::GetShapeDim( ancestor ) == dimToClean ) + { // PAL8021. do not go upper than SOLID, else ComputeStateEngine(CLEAN) // will erase mesh on other shapes in a compound - if ( ancestor.ShapeType() >= TopAbs_SOLID ) { - SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor); - if (aSubMesh) - aSubMesh->ComputeStateEngine(CLEAN); - } + if ( ancestor.ShapeType() >= TopAbs_SOLID && + !ancestors[ iA ]->IsEmpty() ) // prevent infinite CLEAN via event lesteners + ancestors[ iA ]->ComputeStateEngine(CLEAN); } } } -//============================================================================= -/*! - * - */ -//============================================================================= +//======================================================================= +//function : removeSubMeshElementsAndNodes +//purpose : +//======================================================================= -void SMESH_subMesh::RemoveSubMeshElementsAndNodes() +void SMESH_subMesh::removeSubMeshElementsAndNodes() { - //SCRUTE(_subShape.ShapeType()); - cleanSubMesh( this ); // algo may bind a submesh not to _subShape, eg 3D algo @@ -1772,46 +2096,60 @@ void SMESH_subMesh::RemoveSubMeshElementsAndNodes() } //======================================================================= -//function : GetCollection +//function : getCollection //purpose : return a shape containing all sub-shapes of the MainShape that can be // meshed at once along with _subShape //======================================================================= -TopoDS_Shape SMESH_subMesh::GetCollection(SMESH_Gen * theGen, SMESH_Algo* theAlgo) +TopoDS_Shape SMESH_subMesh::getCollection(SMESH_Gen * theGen, + SMESH_Algo* theAlgo, + bool & theSubComputed, + bool & theSubFailed, + std::vector& theSubs) { - MESSAGE("SMESH_subMesh::GetCollection"); + theSubComputed = SubMeshesComputed( & theSubFailed ); TopoDS_Shape mainShape = _father->GetMeshDS()->ShapeToMesh(); if ( mainShape.IsSame( _subShape )) return _subShape; - const bool ignoreAuxiliaryHyps = false; + const bool skipAuxHyps = false; list aUsedHyp = - theAlgo->GetUsedHypothesis( *_father, _subShape, ignoreAuxiliaryHyps ); // copy + theAlgo->GetUsedHypothesis( *_father, _subShape, skipAuxHyps ); // copy // put in a compound all shapes with the same hypothesis assigned - // and a good ComputState + // and a good ComputeState TopoDS_Compound aCompound; BRep_Builder aBuilder; aBuilder.MakeCompound( aCompound ); - TopExp_Explorer anExplorer( mainShape, _subShape.ShapeType() ); - for ( ; anExplorer.More(); anExplorer.Next() ) + theSubs.clear(); + + SMESH_subMeshIteratorPtr smIt = _father->GetSubMesh( mainShape )->getDependsOnIterator(false); + while ( smIt->more() ) { - const TopoDS_Shape& S = anExplorer.Current(); - SMESH_subMesh* subMesh = _father->GetSubMesh( S ); + SMESH_subMesh* subMesh = smIt->next(); + const TopoDS_Shape& S = subMesh->_subShape; + if ( S.ShapeType() != this->_subShape.ShapeType() ) + continue; if ( subMesh == this ) { aBuilder.Add( aCompound, S ); + theSubs.push_back( subMesh ); } else if ( subMesh->GetComputeState() == READY_TO_COMPUTE ) { - SMESH_Algo* anAlgo = theGen->GetAlgo( *_father, S ); - if (anAlgo == theAlgo && - anAlgo->GetUsedHypothesis( *_father, S, ignoreAuxiliaryHyps ) == aUsedHyp) + SMESH_Algo* anAlgo = subMesh->GetAlgo(); + if (( anAlgo->IsSameName( *theAlgo )) && // same algo + ( anAlgo->GetUsedHypothesis( *_father, S, skipAuxHyps ) == aUsedHyp )) // same hyps + { aBuilder.Add( aCompound, S ); + if ( !subMesh->SubMeshesComputed() ) + theSubComputed = false; + theSubs.push_back( subMesh ); + } } } @@ -1819,14 +2157,14 @@ TopoDS_Shape SMESH_subMesh::GetCollection(SMESH_Gen * theGen, SMESH_Algo* theAlg } //======================================================================= -//function : GetSimilarAttached +//function : getSimilarAttached //purpose : return a hypothesis attached to theShape. // If theHyp is provided, similar but not same hypotheses // is returned; else only applicable ones having theHypType // is returned //======================================================================= -const SMESH_Hypothesis* SMESH_subMesh::GetSimilarAttached(const TopoDS_Shape& theShape, +const SMESH_Hypothesis* SMESH_subMesh::getSimilarAttached(const TopoDS_Shape& theShape, const SMESH_Hypothesis * theHyp, const int theHypType) { @@ -1848,18 +2186,16 @@ const SMESH_Hypothesis* SMESH_subMesh::GetSimilarAttached(const TopoDS_Shape& } //======================================================================= -//function : CheckConcurentHypothesis +//function : CheckConcurrentHypothesis //purpose : check if there are several applicable hypothesis attached to // ancestors //======================================================================= SMESH_Hypothesis::Hypothesis_Status - SMESH_subMesh::CheckConcurentHypothesis (const int theHypType) + SMESH_subMesh::CheckConcurrentHypothesis (const int theHypType) { - MESSAGE ("SMESH_subMesh::CheckConcurentHypothesis"); - // is there local hypothesis on me? - if ( GetSimilarAttached( _subShape, 0, theHypType ) ) + if ( getSimilarAttached( _subShape, 0, theHypType ) ) return SMESH_Hypothesis::HYP_OK; @@ -1869,7 +2205,7 @@ SMESH_Hypothesis::Hypothesis_Status for (; it.More(); it.Next()) { const TopoDS_Shape& ancestor = it.Value(); - const SMESH_Hypothesis* hyp = GetSimilarAttached( ancestor, 0, theHypType ); + const SMESH_Hypothesis* hyp = getSimilarAttached( ancestor, 0, theHypType ); if ( hyp ) { if ( aPrevWithHyp.IsNull() || aPrevWithHyp.IsSame( ancestor )) @@ -1878,7 +2214,7 @@ SMESH_Hypothesis::Hypothesis_Status aPrevHyp = hyp; } else if ( aPrevWithHyp.ShapeType() == ancestor.ShapeType() && aPrevHyp != hyp ) - return SMESH_Hypothesis::HYP_CONCURENT; + return SMESH_Hypothesis::HYP_CONCURRENT; else return SMESH_Hypothesis::HYP_OK; } @@ -1886,14 +2222,26 @@ SMESH_Hypothesis::Hypothesis_Status return SMESH_Hypothesis::HYP_OK; } +//================================================================================ +/*! + * \brief Constructor of OwnListenerData + */ +//================================================================================ + +SMESH_subMesh::OwnListenerData::OwnListenerData( SMESH_subMesh* sm, EventListener* el): + mySubMesh( sm ), + myMeshID( sm ? sm->GetFather()->GetId() : -1 ), + mySubMeshID( sm ? sm->GetId() : -1 ), + myListener( el ) +{ +} + //================================================================================ /*! * \brief Sets an event listener and its data to a submesh * \param listener - the listener to store * \param data - the listener data to store * \param where - the submesh to store the listener and it's data - * \param deleteListener - if true then the listener will be deleted as - * it is removed from where submesh * * It remembers the submesh where it puts the listener in order to delete * them when HYP_OK algo_state is lost @@ -1906,8 +2254,8 @@ void SMESH_subMesh::SetEventListener(EventListener* listener, SMESH_subMesh* where) { if ( listener && where ) { - where->SetEventListener( listener, data ); - myOwnListeners.push_back( make_pair( where, listener )); + where->setEventListener( listener, data ); + _ownListeners.push_back( OwnListenerData( where, listener )); } } @@ -1921,55 +2269,130 @@ void SMESH_subMesh::SetEventListener(EventListener* listener, */ //================================================================================ -void SMESH_subMesh::SetEventListener(EventListener* listener, EventListenerData* data) +void SMESH_subMesh::setEventListener(EventListener* listener, + EventListenerData* data) { map< EventListener*, EventListenerData* >::iterator l_d = - myEventListeners.find( listener ); - if ( l_d != myEventListeners.end() ) { + _eventListeners.find( listener ); + if ( l_d != _eventListeners.end() ) { EventListenerData* curData = l_d->second; + l_d->second = data; if ( curData && curData != data && curData->IsDeletable() ) delete curData; - l_d->second = data; } - else - myEventListeners.insert( make_pair( listener, data )); + else + { + for ( l_d = _eventListeners.begin(); l_d != _eventListeners.end(); ++l_d ) + if ( listener->GetName() == l_d->first->GetName() ) + { + EventListenerData* curData = l_d->second; + l_d->second = 0; + if ( curData && curData != data && curData->IsDeletable() ) + delete curData; + if ( l_d->first != listener && l_d->first->IsDeletable() ) + delete l_d->first; + _eventListeners.erase( l_d ); + break; + } + _eventListeners.insert( make_pair( listener, data )); + } } //================================================================================ /*! * \brief Return an event listener data * \param listener - the listener whose data is + * \param myOwn - if \c true, returns a listener set by this sub-mesh, + * else returns a listener listening to events of this sub-mesh + * \retval EventListenerData* - found data, maybe NULL + */ +//================================================================================ + +EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener, + const bool myOwn) const +{ + if ( myOwn ) + { + list< OwnListenerData >::const_iterator d; + for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d ) + { + if ( d->myListener == listener && _father->MeshExists( d->myMeshID )) + return d->mySubMesh->GetEventListenerData( listener, !myOwn ); + } + } + else + { + map< EventListener*, EventListenerData* >::const_iterator l_d = + _eventListeners.find( listener ); + if ( l_d != _eventListeners.end() ) + return l_d->second; + } + return 0; +} + +//================================================================================ +/*! + * \brief Return an event listener data + * \param listenerName - the listener name + * \param myOwn - if \c true, returns a listener set by this sub-mesh, + * else returns a listener listening to events of this sub-mesh * \retval EventListenerData* - found data, maybe NULL */ //================================================================================ -EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener) const +EventListenerData* SMESH_subMesh::GetEventListenerData(const string& listenerName, + const bool myOwn) const { - map< EventListener*, EventListenerData* >::const_iterator l_d = - myEventListeners.find( listener ); - if ( l_d != myEventListeners.end() ) - return l_d->second; + if ( myOwn ) + { + list< OwnListenerData >::const_iterator d; + for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d ) + { + if ( _father->MeshExists( d->myMeshID ) && listenerName == d->myListener->GetName()) + return d->mySubMesh->GetEventListenerData( listenerName, !myOwn ); + } + } + else + { + map< EventListener*, EventListenerData* >::const_iterator l_d = _eventListeners.begin(); + for ( ; l_d != _eventListeners.end(); ++l_d ) + if ( listenerName == l_d->first->GetName() ) + return l_d->second; + } return 0; } //================================================================================ /*! - * \brief Notify stored event listeners on the occured event + * \brief Notify stored event listeners on the occurred event * \param event - algo_event or compute_event itself * \param eventType - algo_event or compute_event - * \param subMesh - the submesh where the event occures - * \param data - listener data stored in the subMesh * \param hyp - hypothesis, if eventType is algo_event */ //================================================================================ -void SMESH_subMesh::NotifyListenersOnEvent( const int event, +void SMESH_subMesh::notifyListenersOnEvent( const int event, const event_type eventType, SMESH_Hypothesis* hyp) { - map< EventListener*, EventListenerData* >::iterator l_d = myEventListeners.begin(); - for ( ; l_d != myEventListeners.end(); ++l_d ) - l_d->first->ProcessEvent( event, eventType, this, l_d->second, hyp ); + list< pair< EventListener*, EventListenerData* > > eventListeners( _eventListeners.begin(), + _eventListeners.end()); + list< pair< EventListener*, EventListenerData* > >::iterator l_d = eventListeners.begin(); + for ( ; l_d != eventListeners.end(); ++l_d ) + { + std::pair< EventListener*, EventListenerData* > li_da = *l_d; + if ( !_eventListeners.count( li_da.first )) continue; + + if ( li_da.first->myBusySM.insert( this ).second ) + { + const bool isDeletable = li_da.first->IsDeletable(); + + li_da.first->ProcessEvent( event, eventType, this, li_da.second, hyp ); + + if ( !isDeletable || _eventListeners.count( li_da.first )) + li_da.first->myBusySM.erase( this ); // a listener is hopefully not dead + } + } } //================================================================================ @@ -1982,11 +2405,20 @@ void SMESH_subMesh::NotifyListenersOnEvent( const int event, void SMESH_subMesh::DeleteEventListener(EventListener* listener) { map< EventListener*, EventListenerData* >::iterator l_d = - myEventListeners.find( listener ); - if ( l_d != myEventListeners.end() ) { - if ( l_d->first && l_d->first->IsDeletable() ) delete l_d->first; - if ( l_d->second && l_d->second->IsDeletable() ) delete l_d->second; - myEventListeners.erase( l_d ); + _eventListeners.find( listener ); + if ( l_d != _eventListeners.end() && l_d->first ) + { + if ( l_d->second && l_d->second->IsDeletable() ) + { + delete l_d->second; + } + l_d->first->myBusySM.erase( this ); + if ( l_d->first->IsDeletable() ) + { + l_d->first->BeforeDelete( this, l_d->second ); + delete l_d->first; + } + _eventListeners.erase( l_d ); } } @@ -1996,12 +2428,41 @@ void SMESH_subMesh::DeleteEventListener(EventListener* listener) */ //================================================================================ -void SMESH_subMesh::DeleteOwnListeners() +void SMESH_subMesh::deleteOwnListeners() { - list< pair< SMESH_subMesh*, EventListener* > >::iterator sm_l; - for ( sm_l = myOwnListeners.begin(); sm_l != myOwnListeners.end(); ++sm_l) - sm_l->first->DeleteEventListener( sm_l->second ); - myOwnListeners.clear(); + list< OwnListenerData >::iterator d; + for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d ) + { + SMESH_Mesh* mesh = _father->FindMesh( d->myMeshID ); + if ( !mesh || !mesh->GetSubMeshContaining( d->mySubMeshID )) + continue; + d->mySubMesh->DeleteEventListener( d->myListener ); + } + _ownListeners.clear(); +} + +//======================================================================= +//function : loadDependentMeshes +//purpose : loads dependent meshes on SUBMESH_LOADED event +//======================================================================= + +void SMESH_subMesh::loadDependentMeshes() +{ + list< OwnListenerData >::iterator d; + for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d ) + if ( _father != d->mySubMesh->_father ) + d->mySubMesh->_father->Load(); + + // map< EventListener*, EventListenerData* >::iterator l_d = _eventListeners.begin(); + // for ( ; l_d != _eventListeners.end(); ++l_d ) + // if ( l_d->second ) + // { + // const list& smList = l_d->second->mySubMeshes; + // list::const_iterator sm = smList.begin(); + // for ( ; sm != smList.end(); ++sm ) + // if ( _father != (*sm)->_father ) + // (*sm)->_father->Load(); + // } } //================================================================================ @@ -2009,7 +2470,7 @@ void SMESH_subMesh::DeleteOwnListeners() * \brief Do something on a certain event * \param event - algo_event or compute_event itself * \param eventType - algo_event or compute_event - * \param subMesh - the submesh where the event occures + * \param subMesh - the submesh where the event occurs * \param data - listener data stored in the subMesh * \param hyp - hypothesis, if eventType is algo_event * @@ -2034,9 +2495,10 @@ void SMESH_subMeshEventListener::ProcessEvent(const int event, switch ( event ) { case SMESH_subMesh::CLEAN: for ( ; smIt != smEnd; ++ smIt) - (*smIt)->ComputeStateEngine( event ); + (*smIt)->ComputeStateEngine( SMESH_subMesh::compute_event( event )); break; case SMESH_subMesh::COMPUTE: + case SMESH_subMesh::COMPUTE_SUBMESH: if ( subMesh->GetComputeState() == SMESH_subMesh::COMPUTE_OK ) for ( ; smIt != smEnd; ++ smIt) (*smIt)->ComputeStateEngine( SMESH_subMesh::SUBMESH_COMPUTED ); @@ -2058,9 +2520,10 @@ namespace { { _Iterator(SMDS_Iterator* subIt, SMESH_subMesh* prepend, - SMESH_subMesh* append): myIt(subIt),myAppend(append) + SMESH_subMesh* append): myAppend(append), myIt(subIt) { - myCur = prepend ? prepend : myIt->more() ? myIt->next() : 0; + myCur = prepend ? prepend : myIt->more() ? myIt->next() : append; + if ( myCur == append ) append = 0; } /// Return true if and only if there are other object in this iterator virtual bool more() @@ -2086,28 +2549,100 @@ namespace { //================================================================================ /*! - * \brief Return iterator on the submeshes this one depends on - * \param includeSelf - this submesh to be returned also - * \param reverse - if true, complex shape submeshes go first + * \brief Return iterator on the submeshes this one depends on + * \param includeSelf - this submesh to be returned also + * \param reverse - if true, complex shape submeshes go first */ //================================================================================ SMESH_subMeshIteratorPtr SMESH_subMesh::getDependsOnIterator(const bool includeSelf, - const bool reverse) + const bool reverse) const { + SMESH_subMesh *me = (SMESH_subMesh*) this; SMESH_subMesh *prepend=0, *append=0; if ( includeSelf ) { - if ( reverse ) prepend = this; - else append = this; + if ( reverse ) prepend = me; + else append = me; } typedef map < int, SMESH_subMesh * > TMap; if ( reverse ) { return SMESH_subMeshIteratorPtr - ( new _Iterator( new SMDS_mapReverseIterator( DependsOn() ), prepend, append )); + ( new _Iterator( new SMDS_mapReverseIterator( me->DependsOn() ), prepend, append )); } { return SMESH_subMeshIteratorPtr - ( new _Iterator( new SMDS_mapIterator( DependsOn() ), prepend, append )); + ( new _Iterator( new SMDS_mapIterator( me->DependsOn() ), prepend, append )); + } +} + +//================================================================================ +/*! + * \brief Returns ancestor sub-meshes. Finds them if not yet found. + */ +//================================================================================ + +const std::vector< SMESH_subMesh * > & SMESH_subMesh::GetAncestors() const +{ + if ( _ancestors.empty() && + !_subShape.IsSame( _father->GetShapeToMesh() )) + { + const TopTools_ListOfShape& ancShapes = _father->GetAncestors( _subShape ); + + SMESH_subMesh* me = const_cast< SMESH_subMesh* >( this ); + me->_ancestors.reserve( ancShapes.Extent() ); + + // assure that all sub-meshes exist + TopoDS_Shape mainShape = _father->GetShapeToMesh(); + if ( !mainShape.IsNull() ) + _father->GetSubMesh( mainShape )->DependsOn(); + + TopTools_MapOfShape map; + + for ( TopTools_ListIteratorOfListOfShape it( ancShapes ); it.More(); it.Next() ) + if ( SMESH_subMesh* sm = _father->GetSubMeshContaining( it.Value() )) + if ( map.Add( it.Value() )) + me->_ancestors.push_back( sm ); } + + return _ancestors; +} + +//================================================================================ +/*! + * \brief Clears the vector of ancestor sub-meshes + */ +//================================================================================ + +void SMESH_subMesh::ClearAncestors() +{ + _ancestors.clear(); +} + +//================================================================================ +/*! + * \brief Find common submeshes (based on shared sub-shapes with other + * \param theOther submesh to check + * \param theSetOfCommon set of common submesh + */ +//================================================================================ + +bool SMESH_subMesh::FindIntersection(const SMESH_subMesh* theOther, + std::set& theSetOfCommon ) const +{ + size_t oldNb = theSetOfCommon.size(); + + // check main submeshes + const map ::const_iterator otherEnd = theOther->_mapDepend.end(); + if ( theOther->_mapDepend.find(this->GetId()) != otherEnd ) + theSetOfCommon.insert( this ); + if ( _mapDepend.find(theOther->GetId()) != _mapDepend.end() ) + theSetOfCommon.insert( theOther ); + + // check common submeshes + map ::const_iterator mapIt = _mapDepend.begin(); + for( ; mapIt != _mapDepend.end(); mapIt++ ) + if ( theOther->_mapDepend.find((*mapIt).first) != otherEnd ) + theSetOfCommon.insert( (*mapIt).second ); + return oldNb < theSetOfCommon.size(); }