// SMESH SMESH : implementaion of SMESH idl descriptions // // Copyright (C) 2003 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 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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org // // // // File : SMESH_subMesh.cxx // Author : Paul RASCLE, EDF // Module : SMESH // $Header$ using namespace std; #include "SMESH_subMesh.hxx" #include "SMESH_Gen.hxx" #include "SMESH_Mesh.hxx" #include "SMESH_Hypothesis.hxx" #include "SMESH_Algo.hxx" #include "utilities.h" #include "OpUtil.hxx" #include #include #include #include #include #include #include #ifdef _DEBUG_ #include #include #include #endif //============================================================================= /*! * default constructor: */ //============================================================================= SMESH_subMesh::SMESH_subMesh(int Id, SMESH_Mesh * father, SMESHDS_Mesh * meshDS, const TopoDS_Shape & aSubShape) { _subShape = aSubShape; _meshDS = meshDS; _subMeshDS = meshDS->MeshElements(_subShape); // may be null ... _father = father; _Id = Id; _dependenceAnalysed = false; if (_subShape.ShapeType() == TopAbs_VERTEX) { _algoState = HYP_OK; _computeState = READY_TO_COMPUTE; } else { _algoState = NO_ALGO; _computeState = NOT_READY; } } //============================================================================= /*! * */ //============================================================================= SMESH_subMesh::~SMESH_subMesh() { MESSAGE("SMESH_subMesh::~SMESH_subMesh"); // **** } //============================================================================= /*! * */ //============================================================================= int SMESH_subMesh::GetId() const { //MESSAGE("SMESH_subMesh::GetId"); return _Id; } //============================================================================= /*! * */ //============================================================================= SMESHDS_SubMesh * SMESH_subMesh::GetSubMeshDS() { //MESSAGE("SMESH_subMesh::GetSubMeshDS"); if (_subMeshDS==NULL) { //MESSAGE("subMesh pointer still null, trying to get it..."); _subMeshDS = _meshDS->MeshElements(_subShape); // may be null ... if (_subMeshDS==NULL) { MESSAGE("problem... subMesh still empty"); //NRI ASSERT(0); //NRI throw SALOME_Exception(LOCALIZED(subMesh still empty)); } } return _subMeshDS; } //============================================================================= /*! * */ //============================================================================= SMESHDS_SubMesh* SMESH_subMesh::CreateSubMeshDS() { if ( !GetSubMeshDS() ) _meshDS->NewSubMesh( _meshDS->ShapeToIndex( _subShape ) ); return GetSubMeshDS(); } //============================================================================= /*! * */ //============================================================================= SMESH_subMesh *SMESH_subMesh::GetFirstToCompute() { //MESSAGE("SMESH_subMesh::GetFirstToCompute"); const map < int, SMESH_subMesh * >&subMeshes = DependsOn(); SMESH_subMesh *firstToCompute = 0; map < int, SMESH_subMesh * >::const_iterator itsub; for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++) { SMESH_subMesh *sm = (*itsub).second; // SCRUTE(sm->GetId()); // SCRUTE(sm->GetComputeState()); bool readyToCompute = (sm->GetComputeState() == READY_TO_COMPUTE); if (readyToCompute) { firstToCompute = sm; //SCRUTE(sm->GetId()); break; } } if (firstToCompute) { return firstToCompute; // a subMesh of this } if (_computeState == READY_TO_COMPUTE) { return this; // this } return 0; // nothing to compute } //============================================================================= /*! * */ //============================================================================= bool SMESH_subMesh::SubMeshesComputed() { //MESSAGE("SMESH_subMesh::SubMeshesComputed"); const map < int, SMESH_subMesh * >&subMeshes = DependsOn(); bool subMeshesComputed = true; map < int, SMESH_subMesh * >::const_iterator itsub; for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++) { SMESH_subMesh *sm = (*itsub).second; const TopoDS_Shape & ss = sm->GetSubShape(); int type = ss.ShapeType(); bool computeOk = (sm->GetComputeState() == COMPUTE_OK); if (!computeOk) { 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; } } break; } } return subMeshesComputed; } //============================================================================= /*! * */ //============================================================================= bool SMESH_subMesh::SubMeshesReady() { MESSAGE("SMESH_subMesh::SubMeshesReady"); const map < int, SMESH_subMesh * >&subMeshes = DependsOn(); bool subMeshesReady = true; map < int, SMESH_subMesh * >::const_iterator itsub; for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++) { SMESH_subMesh *sm = (*itsub).second; bool computeOk = ((sm->GetComputeState() == COMPUTE_OK) || (sm->GetComputeState() == READY_TO_COMPUTE)); if (!computeOk) { subMeshesReady = false; SCRUTE(sm->GetId()); break; } } return subMeshesReady; } //============================================================================= /*! * 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. */ //============================================================================= const map < int, SMESH_subMesh * >&SMESH_subMesh::DependsOn() { if (_dependenceAnalysed) return _mapDepend; //MESSAGE("SMESH_subMesh::DependsOn"); int type = _subShape.ShapeType(); //SCRUTE(type); switch (type) { case TopAbs_COMPOUND: { //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"); for (TopExp_Explorer exp(_subShape, TopAbs_FACE); exp.More(); exp.Next()) { InsertDependence(exp.Current()); } 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; } } _dependenceAnalysed = true; return _mapDepend; } //============================================================================= /*! * For simple Shapes (solid, face, edge): add subMesh into dependence list. */ //============================================================================= void SMESH_subMesh::InsertDependence(const TopoDS_Shape aSubShape) { //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()) { _mapDepend[cle] = aSubMesh; const map < int, SMESH_subMesh * >&subMap = aSubMesh->DependsOn(); map < int, SMESH_subMesh * >::const_iterator im; for (im = subMap.begin(); im != subMap.end(); im++) { int clesub = (*im).first; SMESH_subMesh *sm = (*im).second; if (_mapDepend.find(clesub) == _mapDepend.end()) _mapDepend[clesub] = sm; } } } //============================================================================= /*! * */ //============================================================================= const TopoDS_Shape & SMESH_subMesh::GetSubShape() { //MESSAGE("SMESH_subMesh::GetSubShape"); return _subShape; } //======================================================================= //function : CanAddHypothesis //purpose : return true if theHypothesis can be attached to me: // its dimention is checked //======================================================================= bool SMESH_subMesh::CanAddHypothesis(const SMESH_Hypothesis* theHypothesis) const { int aHypDim = theHypothesis->GetDim(); int aShapeDim = SMESH_Gen::GetShapeDim(_subShape); if ( aHypDim <= aShapeDim ) return true; // if ( aHypDim < aShapeDim ) // return ( _father->IsMainShape( _subShape )); return false; } //======================================================================= //function : IsApplicableHypotesis //purpose : return true if theHypothesis can be used to mesh me: // its shape type is checked //======================================================================= bool SMESH_subMesh::IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis) const { if ( theHypothesis->GetType() > SMESHDS_Hypothesis::PARAM_ALGO) // algorithm return ( theHypothesis->GetShapeType() & (1<< _subShape.ShapeType())); // hypothesis switch ( _subShape.ShapeType() ) { case TopAbs_EDGE: case TopAbs_FACE: case TopAbs_SHELL: case TopAbs_SOLID: { int aHypDim = theHypothesis->GetDim(); int aShapeDim = SMESH_Gen::GetShapeDim(_subShape); return ( aHypDim == aShapeDim ); } // case TopAbs_VERTEX: // case TopAbs_WIRE: // case TopAbs_COMPSOLID: // case TopAbs_COMPOUND: default:; } return false; } //============================================================================= /*! * */ //============================================================================= SMESH_Hypothesis::Hypothesis_Status SMESH_subMesh::AlgoStateEngine(int event, SMESH_Hypothesis * anHyp) { // MESSAGE("SMESH_subMesh::AlgoStateEngine"); //SCRUTE(_algoState); //SCRUTE(event); SMESH_Hypothesis::Hypothesis_Status aux_ret, ret = SMESH_Hypothesis::HYP_OK; // **** 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 int dim = SMESH_Gen::GetShapeDim(_subShape); if (dim < 1) { _algoState = HYP_OK; if (event == ADD_HYP || event == ADD_ALGO) return SMESH_Hypothesis::HYP_BAD_DIM; // do not allow to assign any hyp else return SMESH_Hypothesis::HYP_OK; } SMESH_Gen* gen =_father->GetGen(); // bool ret = false; int oldAlgoState = _algoState; bool modifiedHyp = false; // if set to true, force event MODIF_ALGO_STATE // in ComputeStateEngine // ---------------------- // check mesh conformity // ---------------------- if (event == ADD_ALGO) { if (IsApplicableHypotesis( anHyp ) && !_father->IsNotConformAllowed() && !IsConform( static_cast< SMESH_Algo* >( anHyp ))) return SMESH_Hypothesis::HYP_NOTCONFORM; } // ---------------------------------- // add a hypothesis to DS if possible // ---------------------------------- if (event == ADD_HYP || event == ADD_ALGO) { if ( ! CanAddHypothesis( anHyp )) return SMESH_Hypothesis::HYP_BAD_DIM; if ( GetSimilarAttached( _subShape, anHyp ) ) return SMESH_Hypothesis::HYP_ALREADY_EXIST; if ( !_meshDS->AddHypothesis(_subShape, anHyp)) return SMESH_Hypothesis::HYP_ALREADY_EXIST; } // -------------------------- // remove a hypothesis from DS // -------------------------- if (event == REMOVE_HYP || event == REMOVE_ALGO) { if (!_meshDS->RemoveHypothesis(_subShape, anHyp)) return SMESH_Hypothesis::HYP_OK; // nothing changes } // ------------------ // analyse algo state // ------------------ if (!IsApplicableHypotesis( anHyp )) return ret; // not applicable hypotheses do not change algo state switch (_algoState) { // ---------------------------------------------------------------------- case NO_ALGO: switch (event) { case ADD_HYP: break; case ADD_ALGO: { SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); ASSERT(algo); if (algo->CheckHypothesis((*_father),_subShape, aux_ret)) SetAlgoState(HYP_OK); else SetAlgoState(MISSING_HYP); break; } case REMOVE_HYP: break; case REMOVE_ALGO: break; case ADD_FATHER_HYP: break; case ADD_FATHER_ALGO: { // Algo just added in father SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); ASSERT(algo); if ( algo == anHyp ) { if ( algo->CheckHypothesis((*_father),_subShape, aux_ret)) SetAlgoState(HYP_OK); else SetAlgoState(MISSING_HYP); } break; } case REMOVE_FATHER_HYP: break; case REMOVE_FATHER_ALGO: { SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); if (algo) { if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) SetAlgoState(HYP_OK); else SetAlgoState(MISSING_HYP); } break; } default: ASSERT(0); break; } break; // ---------------------------------------------------------------------- case MISSING_HYP: switch (event) { case ADD_HYP: { SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, ret )) SetAlgoState(HYP_OK); if (SMESH_Hypothesis::IsStatusFatal( ret )) _meshDS->RemoveHypothesis(_subShape, anHyp); else if (!_father->IsUsedHypothesis( anHyp, _subShape )) { _meshDS->RemoveHypothesis(_subShape, anHyp); ret = SMESH_Hypothesis::HYP_INCOMPATIBLE; } break; } case ADD_ALGO: { //already existing algo : on father ? SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))// ignore hyp status SetAlgoState(HYP_OK); else SetAlgoState(MISSING_HYP); break; } case REMOVE_HYP: break; case REMOVE_ALGO: { // perhaps a father algo applies ? SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); if (algo == NULL) // no more algo applying on subShape... { SetAlgoState(NO_ALGO); } else { if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) SetAlgoState(HYP_OK); else SetAlgoState(MISSING_HYP); } break; } case ADD_FATHER_HYP: { SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) SetAlgoState(HYP_OK); else SetAlgoState(MISSING_HYP); } break; case ADD_FATHER_ALGO: { // new father algo SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); ASSERT( algo ); if ( algo == anHyp ) { if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) SetAlgoState(HYP_OK); else SetAlgoState(MISSING_HYP); } break; } case REMOVE_FATHER_HYP: // nothing to do break; case REMOVE_FATHER_ALGO: { SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); if (algo == NULL) // no more applying algo on father { SetAlgoState(NO_ALGO); } else { if ( algo->CheckHypothesis((*_father),_subShape , aux_ret )) SetAlgoState(HYP_OK); else SetAlgoState(MISSING_HYP); } break; } default: ASSERT(0); break; } break; // ---------------------------------------------------------------------- case HYP_OK: switch (event) { case ADD_HYP: { SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); ASSERT(algo); if (!algo->CheckHypothesis((*_father),_subShape, ret )) { MESSAGE("two applying algo on the same shape not allowed"); _meshDS->RemoveHypothesis(_subShape, anHyp); if ( !SMESH_Hypothesis::IsStatusFatal( ret )) // ret should be fatal: anHyp was not added ret = SMESH_Hypothesis::HYP_INCOMPATIBLE; } else if (SMESH_Hypothesis::IsStatusFatal( ret )) { _meshDS->RemoveHypothesis(_subShape, anHyp); } else if (!_father->IsUsedHypothesis( anHyp, _subShape )) { _meshDS->RemoveHypothesis(_subShape, anHyp); ret = SMESH_Hypothesis::HYP_INCOMPATIBLE; } else { modifiedHyp = true; } break; } case ADD_ALGO: { //already existing algo : on father ? SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) SetAlgoState(HYP_OK); else SetAlgoState(MISSING_HYP); modifiedHyp = true; break; } case REMOVE_HYP: { SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) SetAlgoState(HYP_OK); else SetAlgoState(MISSING_HYP); modifiedHyp = true; break; } case REMOVE_ALGO: { // perhaps a father algo applies ? SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); if (algo == NULL) // no more algo applying on subShape... { SetAlgoState(NO_ALGO); } else { if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) SetAlgoState(HYP_OK); else SetAlgoState(MISSING_HYP); // check if same algo remains if ( anHyp != algo && strcmp( anHyp->GetName(), algo->GetName()) ) modifiedHyp = true; } break; } case ADD_FATHER_HYP: { // new father hypothesis ? SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) { SetAlgoState(HYP_OK); if (_father->IsUsedHypothesis( anHyp, _subShape )) // new Hyp modifiedHyp = true; } else SetAlgoState(MISSING_HYP); break; } case ADD_FATHER_ALGO: { // a new algo on father SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); if ( algo == anHyp ) { if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) SetAlgoState(HYP_OK); else SetAlgoState(MISSING_HYP); modifiedHyp = true; } break; } case REMOVE_FATHER_HYP: { SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) SetAlgoState(HYP_OK); else SetAlgoState(MISSING_HYP); // is there the same local hyp or maybe a new father algo applied? if ( !GetSimilarAttached( _subShape, anHyp ) ) modifiedHyp = true; break; } case REMOVE_FATHER_ALGO: { SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape); if (algo == NULL) // no more applying algo on father { SetAlgoState(NO_ALGO); } else { if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) SetAlgoState(HYP_OK); else SetAlgoState(MISSING_HYP); // is there the same local algo or maybe a new father algo applied? if ( !GetSimilarAttached( _subShape, anHyp )) modifiedHyp = true; } break; } default: ASSERT(0); break; } break; // ---------------------------------------------------------------------- default: ASSERT(0); break; } // ---------------------------------------- // check concurent hypotheses on ansestors // ---------------------------------------- if (ret < SMESH_Hypothesis::HYP_CONCURENT && (event == ADD_FATHER_HYP || event == ADD_FATHER_ALGO || event == REMOVE_FATHER_HYP || event == REMOVE_FATHER_ALGO || event == REMOVE_ALGO || event == REMOVE_HYP)) { ret = CheckConcurentHypothesis( anHyp->GetType() ); } if ((_algoState != oldAlgoState) || modifiedHyp) int retc = ComputeStateEngine(MODIF_ALGO_STATE); return ret; } //======================================================================= //function : IsConform //purpose : check if a conform mesh will be produced by the Algo //======================================================================= bool SMESH_subMesh::IsConform(const SMESH_Algo* theAlgo) { // MESSAGE( "SMESH_subMesh::IsConform" ); if ( !theAlgo ) return false; // check only algo that doesn't NeedDescretBoundary(): because mesh made // on a sub-shape will be ignored by theAlgo if ( theAlgo->NeedDescretBoundary() ) return true; SMESH_Gen* gen =_father->GetGen(); // only local algo is to be checked if ( gen->IsGlobalAlgo( theAlgo, *_father )) return true; // check algo attached to adjacent shapes // loop on one level down sub-meshes TopoDS_Iterator itsub( _subShape ); for (; itsub.More(); itsub.Next()) { // loop on adjacent subShapes TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( itsub.Value() )); for (; it.More(); it.Next()) { const TopoDS_Shape& adjacent = it.Value(); if ( _subShape.IsSame( adjacent )) continue; if ( adjacent.ShapeType() != _subShape.ShapeType()) break; // check algo attached to smAdjacent SMESH_Algo * algo = gen->GetAlgo((*_father), adjacent); if (algo && //algo != theAlgo && !algo->NeedDescretBoundary() /*&& !gen->IsGlobalAlgo( algo, *_father )*/) return false; // NOT CONFORM MESH WILL BE PRODUCED } } return true; } //============================================================================= /*! * */ //============================================================================= void SMESH_subMesh::SetAlgoState(int state) { // if (state != _oldAlgoState) // int retc = ComputeStateEngine(MODIF_ALGO_STATE); _algoState = state; } //============================================================================= /*! * */ //============================================================================= SMESH_Hypothesis::Hypothesis_Status SMESH_subMesh::SubMeshesAlgoStateEngine(int event, SMESH_Hypothesis * anHyp) { //MESSAGE("SMESH_subMesh::SubMeshesAlgoStateEngine"); SMESH_Hypothesis::Hypothesis_Status ret = SMESH_Hypothesis::HYP_OK; //EAP: a wire (dim==1) should notify edges (dim==1) //EAP: int dim = SMESH_Gen::GetShapeDim(_subShape); if (/*EAP:dim > 1*/ _subShape.ShapeType() < TopAbs_EDGE ) { 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; SMESH_Hypothesis::Hypothesis_Status ret2 = sm->AlgoStateEngine(event, anHyp); if ( ret2 > ret ) ret = ret2; } } return ret; } //============================================================================= /*! * */ //============================================================================= void SMESH_subMesh::CleanDependsOn() { MESSAGE("SMESH_subMesh::CleanDependsOn"); // **** parcourir les ancetres dans l'ordre de dépendance ComputeStateEngine(CLEAN); const map < int, SMESH_subMesh * >&dependson = DependsOn(); map < int, SMESH_subMesh * >::const_iterator its; for (its = dependson.begin(); its != dependson.end(); its++) { SMESH_subMesh *sm = (*its).second; SCRUTE((*its).first); sm->ComputeStateEngine(CLEAN); } } //============================================================================= /*! * */ //============================================================================= void SMESH_subMesh::DumpAlgoState(bool isMain) { 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; } } //============================================================================= /*! * */ //============================================================================= bool SMESH_subMesh::ComputeStateEngine(int event) { //MESSAGE("SMESH_subMesh::ComputeStateEngine"); //SCRUTE(_computeState); //SCRUTE(event); int dim = SMESH_Gen::GetShapeDim(_subShape); if (dim < 1) { if ( IsMeshComputed() ) _computeState = COMPUTE_OK; else _computeState = READY_TO_COMPUTE; return true; } SMESH_Gen *gen = _father->GetGen(); SMESH_Algo *algo = 0; bool ret = true; SMESH_Hypothesis::Hypothesis_Status hyp_status; switch (_computeState) { // ---------------------------------------------------------------------- case NOT_READY: switch (event) { case MODIF_HYP: // nothing to do break; case MODIF_ALGO_STATE: if (_algoState == HYP_OK) { _computeState = READY_TO_COMPUTE; } break; case COMPUTE: // nothing to do break; case CLEAN: RemoveSubMeshElementsAndNodes(); break; case CLEANDEP: CleanDependants(); break; case SUBMESH_COMPUTED: // nothing to do break; case SUBMESH_RESTORED: ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE ); break; case MESH_ENTITY_REMOVED: break; case CHECK_COMPUTE_STATE: if ( IsMeshComputed() ) _computeState = COMPUTE_OK; break; default: ASSERT(0); break; } break; // ---------------------------------------------------------------------- case READY_TO_COMPUTE: switch (event) { case MODIF_HYP: // nothing to do break; case MODIF_ALGO_STATE: _computeState = NOT_READY; algo = gen->GetAlgo((*_father), _subShape); if (algo) { ret = algo->CheckHypothesis((*_father), _subShape, hyp_status); if (ret) _computeState = READY_TO_COMPUTE; } break; case COMPUTE: { algo = gen->GetAlgo((*_father), _subShape); ASSERT(algo); ret = algo->CheckHypothesis((*_father), _subShape, hyp_status); if (!ret) { MESSAGE("***** verify compute state *****"); _computeState = NOT_READY; break; } // check submeshes needed if (algo->NeedDescretBoundary()) ret = SubMeshesComputed(); if (!ret) { MESSAGE("Some SubMeshes not computed"); _computeState = FAILED_TO_COMPUTE; break; } RemoveSubMeshElementsAndNodes(); // compute if (!algo->NeedDescretBoundary() && !algo->OnlyUnaryInput()) ret = ApplyToCollection( algo, GetCollection( gen, algo ) ); else ret = algo->Compute((*_father), _subShape); if (!ret) { MESSAGE("problem in algo execution: failed to compute"); _computeState = FAILED_TO_COMPUTE; if (!algo->NeedDescretBoundary()) UpdateSubMeshState( FAILED_TO_COMPUTE ); #ifdef _DEBUG_ // Show vertices location of a failed shape TopExp_Explorer exp( _subShape, TopAbs_VERTEX); for ( ; exp.More(); exp.Next() ) { gp_Pnt P( BRep_Tool::Pnt( TopoDS::Vertex( exp.Current() ))); cout << P.X() << " " << P.Y() << " " << P.Z() << " " << endl; } #endif break; } else { _computeState = COMPUTE_OK; UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED if (!algo->NeedDescretBoundary()) UpdateSubMeshState( COMPUTE_OK ); } } break; case CLEAN: RemoveSubMeshElementsAndNodes(); _computeState = NOT_READY; algo = gen->GetAlgo((*_father), _subShape); if (algo) { ret = algo->CheckHypothesis((*_father), _subShape, hyp_status); if (ret) _computeState = READY_TO_COMPUTE; } break; case CLEANDEP: CleanDependants(); break; case SUBMESH_COMPUTED: // nothing to do break; case SUBMESH_RESTORED: // check if a mesh is already computed that may // happen after retrieval from a file ComputeStateEngine( CHECK_COMPUTE_STATE ); ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE ); break; case MESH_ENTITY_REMOVED: break; case CHECK_COMPUTE_STATE: if ( IsMeshComputed() ) _computeState = COMPUTE_OK; break; default: ASSERT(0); break; } break; // ---------------------------------------------------------------------- case COMPUTE_OK: switch (event) { case MODIF_HYP: CleanDependants(); // recursive recall with event CLEANDEP algo = gen->GetAlgo((*_father), _subShape); if (algo && !algo->NeedDescretBoundary()) CleanDependsOn(); // remove sub-mesh with event CLEANDEP break; case MODIF_ALGO_STATE: CleanDependants(); // recursive recall with event CLEANDEP algo = gen->GetAlgo((*_father), _subShape); if (algo && !algo->NeedDescretBoundary()) CleanDependsOn(); // remove sub-mesh with event CLEANDEP break; case COMPUTE: // nothing to do break; case CLEAN: RemoveSubMeshElementsAndNodes(); _computeState = NOT_READY; algo = gen->GetAlgo((*_father), _subShape); if (algo) { ret = algo->CheckHypothesis((*_father), _subShape, hyp_status); if (ret) _computeState = READY_TO_COMPUTE; } break; case CLEANDEP: CleanDependants(); // recursive recall with event CLEANDEP break; case SUBMESH_COMPUTED: // nothing to do break; case SUBMESH_RESTORED: ComputeStateEngine( CHECK_COMPUTE_STATE ); ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE ); break; case MESH_ENTITY_REMOVED: UpdateDependantsState( CHECK_COMPUTE_STATE ); ComputeStateEngine( CHECK_COMPUTE_STATE ); ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE ); break; case CHECK_COMPUTE_STATE: if ( !IsMeshComputed() ) if (_algoState == HYP_OK) _computeState = READY_TO_COMPUTE; else _computeState = NOT_READY; break; default: ASSERT(0); break; } break; // ---------------------------------------------------------------------- case FAILED_TO_COMPUTE: switch (event) { case MODIF_HYP: if (_algoState == HYP_OK) _computeState = READY_TO_COMPUTE; else _computeState = NOT_READY; break; case MODIF_ALGO_STATE: if (_algoState == HYP_OK) _computeState = READY_TO_COMPUTE; else _computeState = NOT_READY; break; case COMPUTE: // nothing to do break; case CLEAN: RemoveSubMeshElementsAndNodes(); if (_algoState == HYP_OK) _computeState = READY_TO_COMPUTE; else _computeState = NOT_READY; break; case CLEANDEP: CleanDependants(); break; case SUBMESH_COMPUTED: // allow retry compute if (_algoState == HYP_OK) _computeState = READY_TO_COMPUTE; else _computeState = NOT_READY; break; case SUBMESH_RESTORED: ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE ); break; case MESH_ENTITY_REMOVED: break; case CHECK_COMPUTE_STATE: if ( IsMeshComputed() ) _computeState = COMPUTE_OK; else if (_algoState == HYP_OK) _computeState = READY_TO_COMPUTE; else _computeState = NOT_READY; break; default: ASSERT(0); break; } break; // ---------------------------------------------------------------------- default: ASSERT(0); break; } //SCRUTE(_computeState); return ret; } //======================================================================= //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() ); bool ret = false; ret = theAlgo->Compute( *_father, theCollection ); // set _computeState of subshapes TopExp_Explorer anExplorer( theCollection, _subShape.ShapeType() ); for ( ; anExplorer.More(); anExplorer.Next() ) { const TopoDS_Shape& aSubShape = anExplorer.Current(); SMESH_subMesh* subMesh = _father->GetSubMeshContaining( aSubShape ); if ( subMesh ) { if (ret) { subMesh->_computeState = COMPUTE_OK; subMesh->UpdateDependantsState( SUBMESH_COMPUTED ); subMesh->UpdateSubMeshState( COMPUTE_OK ); } else { subMesh->_computeState = FAILED_TO_COMPUTE; } } } return ret; } //======================================================================= //function : UpdateSubMeshState //purpose : //======================================================================= void SMESH_subMesh::UpdateSubMeshState(const compute_state theState) { const map& smMap = DependsOn(); map::const_iterator itsub; for (itsub = smMap.begin(); itsub != smMap.end(); itsub++) { SMESH_subMesh* sm = (*itsub).second; sm->_computeState = theState; } } //======================================================================= //function : ComputeSubMeshStateEngine //purpose : //======================================================================= void SMESH_subMesh::ComputeSubMeshStateEngine(int event) { const map& smMap = DependsOn(); map::const_iterator itsub; for (itsub = smMap.begin(); itsub != smMap.end(); itsub++) { SMESH_subMesh* sm = (*itsub).second; sm->ComputeStateEngine(event); } } //======================================================================= //function : UpdateDependantsState //purpose : //======================================================================= void SMESH_subMesh::UpdateDependantsState(const compute_event theEvent) { //MESSAGE("SMESH_subMesh::UpdateDependantsState"); TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape )); for (; it.More(); it.Next()) { const TopoDS_Shape& ancestor = it.Value(); SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor); if (aSubMesh) aSubMesh->ComputeStateEngine( theEvent ); } } //============================================================================= /*! * */ //============================================================================= void SMESH_subMesh::CleanDependants() { //MESSAGE("SMESH_subMesh::CleanDependants: shape type " << _subShape.ShapeType() ); TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape )); for (; it.More(); it.Next()) { const TopoDS_Shape& ancestor = it.Value(); //MESSAGE("ancestor shape type " << ancestor.ShapeType() ); SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor); if (aSubMesh) aSubMesh->ComputeStateEngine(CLEANDEP); } ComputeStateEngine(CLEAN); } //============================================================================= /*! * */ //============================================================================= static void removeSubMesh( SMESHDS_Mesh * meshDS, const TopoDS_Shape& subShape) { SMESHDS_SubMesh * subMeshDS = meshDS->MeshElements(subShape); if (subMeshDS!=NULL) { SMDS_ElemIteratorPtr ite=subMeshDS->GetElements(); while(ite->more()) { const SMDS_MeshElement * elt = ite->next(); //MESSAGE( " RM elt: "<GetID()<<" ( "<NbNodes()<<" )" ); meshDS->RemoveElement(elt); } SMDS_NodeIteratorPtr itn=subMeshDS->GetNodes(); while(itn->more()) { const SMDS_MeshNode * node = itn->next(); //MESSAGE( " RM node: "<GetID()); meshDS->RemoveNode(node); } } } //============================================================================= /*! * */ //============================================================================= void SMESH_subMesh::RemoveSubMeshElementsAndNodes() { SCRUTE(_subShape.ShapeType()); removeSubMesh( _meshDS, _subShape ); // algo may bind a submesh not to _subShape, eg 3D algo // sets nodes on SHELL while _subShape may be SOLID int dim = SMESH_Gen::GetShapeDim( _subShape ); int type = _subShape.ShapeType() + 1; for ( ; type <= TopAbs_EDGE; type++) if ( dim == SMESH_Gen::GetShapeDim( (TopAbs_ShapeEnum) type )) { TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type ); for ( ; exp.More(); exp.Next() ) removeSubMesh( _meshDS, exp.Current() ); } else break; } //======================================================================= //function : IsMeshComputed //purpose : check if _subMeshDS contains mesh elements //======================================================================= bool SMESH_subMesh::IsMeshComputed() const { // algo may bind a submesh not to _subShape, eg 3D algo // sets nodes on SHELL while _subShape may be SOLID int dim = SMESH_Gen::GetShapeDim( _subShape ); int type = _subShape.ShapeType(); for ( ; type <= TopAbs_VERTEX; type++) { if ( dim == SMESH_Gen::GetShapeDim( (TopAbs_ShapeEnum) type )) { TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type ); for ( ; exp.More(); exp.Next() ) { SMESHDS_SubMesh * subMeshDS = _meshDS->MeshElements( exp.Current() ); if ( subMeshDS != NULL && (subMeshDS->GetElements()->more() || subMeshDS->GetNodes()->more())) { return true; } } } else break; } return false; } //======================================================================= //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) { MESSAGE("SMESH_subMesh::GetCollection"); ASSERT (!theAlgo->NeedDescretBoundary()); TopoDS_Shape mainShape = _father->GetMeshDS()->ShapeToMesh(); if ( mainShape.IsSame( _subShape )) return _subShape; list aUsedHyp = theAlgo->GetUsedHypothesis( *_father, _subShape ); // copy // put in a compound all shapes with the same hypothesis assigned // and a good ComputState TopoDS_Compound aCompound; BRep_Builder aBuilder; aBuilder.MakeCompound( aCompound ); TopExp_Explorer anExplorer( mainShape, _subShape.ShapeType() ); for ( ; anExplorer.More(); anExplorer.Next() ) { const TopoDS_Shape& S = anExplorer.Current(); SMESH_subMesh* subMesh = _father->GetSubMesh( S ); SMESH_Algo* anAlgo = theGen->GetAlgo( *_father, S ); if (subMesh->GetComputeState() == READY_TO_COMPUTE && anAlgo == theAlgo && anAlgo->GetUsedHypothesis( *_father, S ) == aUsedHyp) { aBuilder.Add( aCompound, S ); } } return aCompound; } //======================================================================= //function : GetSimilarAttached //purpose : return nb of hypotheses attached to theShape. // If theHyp is provided, similar but not same hypotheses // are countered; else only applicable ones having theHypType // are countered //======================================================================= const SMESH_Hypothesis* SMESH_subMesh::GetSimilarAttached(const TopoDS_Shape& theShape, const SMESH_Hypothesis * theHyp, const int theHypType) { const list& aHypList = _father->GetHypothesisList( theShape ); list::const_iterator it = aHypList.begin(); for ( ; it != aHypList.end(); it++ ) { const SMESH_Hypothesis* hyp = static_cast< const SMESH_Hypothesis *>( *it ); if ( theHyp ) { // find similar if (hyp != theHyp && hyp->GetType() == theHyp->GetType() && hyp->GetDim() == theHyp->GetDim()) return hyp; } else { if ( hyp->GetType() == theHypType && IsApplicableHypotesis( hyp )) return hyp; } } return 0; } //======================================================================= //function : CheckConcurentHypothesis //purpose : check if there are several applicable hypothesis attached to // ansestors //======================================================================= SMESH_Hypothesis::Hypothesis_Status SMESH_subMesh::CheckConcurentHypothesis (const int theHypType) { MESSAGE ("SMESH_subMesh::CheckConcurentHypothesis"); // is there local hypothesis on me? if ( GetSimilarAttached( _subShape, 0, theHypType ) ) return SMESH_Hypothesis::HYP_OK; TopoDS_Shape aPrevWithHyp; const SMESH_Hypothesis* aPrevHyp = 0; TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape )); for (; it.More(); it.Next()) { const TopoDS_Shape& ancestor = it.Value(); const SMESH_Hypothesis* hyp = GetSimilarAttached( ancestor, 0, theHypType ); if ( hyp ) { if ( aPrevWithHyp.IsNull() || aPrevWithHyp.IsSame( ancestor )) { aPrevWithHyp = ancestor; aPrevHyp = hyp; } else if ( aPrevWithHyp.ShapeType() == ancestor.ShapeType() && aPrevHyp != hyp ) return SMESH_Hypothesis::HYP_CONCURENT; else return SMESH_Hypothesis::HYP_OK; } } return SMESH_Hypothesis::HYP_OK; }