X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FStdMeshers%2FStdMeshers_Propagation.cxx;h=8b88ce99aef3eb996847f48c10b46bc41896652f;hp=f2d982bd1875b2a024a754dd073366b63e2341f5;hb=6650dea1f85dd5c640829d6e0391d703a304a152;hpb=4ff5bd61540272713e48de1eee75625028c32155 diff --git a/src/StdMeshers/StdMeshers_Propagation.cxx b/src/StdMeshers/StdMeshers_Propagation.cxx index f2d982bd1..8b88ce99a 100644 --- a/src/StdMeshers/StdMeshers_Propagation.cxx +++ b/src/StdMeshers/StdMeshers_Propagation.cxx @@ -1,6 +1,7 @@ -// SMESH SMESH : implementaion of SMESH idl descriptions +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003 CEA +// 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 @@ -16,105 +17,579 @@ // 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.org -// -// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + +// SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Propagation.cxx // Module : SMESH -// $Header$ - +// #include "StdMeshers_Propagation.hxx" #include "utilities.h" +#include "SMDS_SetIterator.hxx" +#include "SMESH_Algo.hxx" +#include "SMESH_HypoFilter.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_subMesh.hxx" + +#include +#include +#include +#include + +#define DBGMSG(txt) \ +// cout << txt << endl; + using namespace std; -//============================================================================= -/*! - * - */ -//============================================================================= -StdMeshers_Propagation::StdMeshers_Propagation (int hypId, int studyId, - SMESH_Gen * gen) - : SMESH_Hypothesis(hypId, studyId, gen) -{ - _name = GetName(); - _param_algo_dim = -1; // 1D auxiliary -} +namespace { -//============================================================================= -/*! - * - */ -//============================================================================= -StdMeshers_Propagation::~StdMeshers_Propagation() -{ + // ======================================================================= + /*! + * \brief Listener managing propagation of 1D hypotheses + */ + // ======================================================================= + + class PropagationMgr: public SMESH_subMeshEventListener + { + public: + static PropagationMgr* GetListener(); + /*! + * \brief Set listener on edge submesh + */ + static void Set(SMESH_subMesh * submesh); + /*! + * \brief Return an edge from which hypotheses are propagated from + */ + static TopoDS_Edge GetSource(SMESH_subMesh * submesh); + /*! + * \brief Does it's main job + */ + void ProcessEvent(const int event, + const int eventType, + SMESH_subMesh* subMesh, + SMESH_subMeshEventListenerData* data, + const SMESH_Hypothesis* hyp = 0); + private: + PropagationMgr(); + }; } //============================================================================= /*! - * + * StdMeshers_Propagation Implementation */ //============================================================================= -ostream & StdMeshers_Propagation::SaveTo (ostream & save) +StdMeshers_Propagation::StdMeshers_Propagation (int hypId, int studyId, SMESH_Gen * gen) + : SMESH_Hypothesis(hypId, studyId, gen) { - return save; + _name = GetName(); + _param_algo_dim = -1; // 1D auxiliary } - -//============================================================================= +StdMeshers_Propagation::~StdMeshers_Propagation() {} +string StdMeshers_Propagation::GetName () { return "Propagation"; } +ostream & StdMeshers_Propagation::SaveTo (ostream & save) { return save; } +istream & StdMeshers_Propagation::LoadFrom (istream & load) { return load; } +ostream & operator << (ostream & save, StdMeshers_Propagation & hyp) { return hyp.SaveTo(save); } +istream & operator >> (istream & load, StdMeshers_Propagation & hyp) { return hyp.LoadFrom(load); } +bool StdMeshers_Propagation::SetParametersByMesh(const SMESH_Mesh*, + const TopoDS_Shape& ) { return false; } +bool StdMeshers_Propagation::SetParametersByDefaults(const TDefaults&,const SMESH_Mesh*) { return false; } +void StdMeshers_Propagation::SetPropagationMgr(SMESH_subMesh* subMesh) { PropagationMgr::Set( subMesh ); } /*! - * + * \brief Return an edge from which hypotheses are propagated from */ -//============================================================================= -istream & StdMeshers_Propagation::LoadFrom (istream & load) +TopoDS_Edge StdMeshers_Propagation::GetPropagationSource(SMESH_Mesh& theMesh, + const TopoDS_Shape& theEdge) { - return load; + return PropagationMgr::GetSource(theMesh.GetSubMeshContaining( theEdge )); } //============================================================================= -/*! - * - */ //============================================================================= -ostream & operator << (ostream & save, StdMeshers_Propagation & hyp) -{ - return hyp.SaveTo(save); -} - +// PROPAGATION MANAGEMENT //============================================================================= -/*! - * - */ //============================================================================= -istream & operator >> (istream & load, StdMeshers_Propagation & hyp) -{ - return hyp.LoadFrom(load); -} -//============================================================================= -/*! - * GetName - */ -//============================================================================= -std::string StdMeshers_Propagation::GetName () -{ - return "Propagation"; -} -//================================================================================ -/*! - * \brief Initialize my parameter values by the mesh built on the geometry - * \param theMesh - the built mesh - * \param theShape - the geometry of interest - * \retval bool - true if parameter values have been successfully defined - * - * Just return false as this hypothesis does not have parameters values - */ -//================================================================================ +namespace { -bool StdMeshers_Propagation::SetParametersByMesh(const SMESH_Mesh* /*theMesh*/, - const TopoDS_Shape& /*theShape*/) -{ - return false; -} + enum SubMeshState { WAIT_PROPAG_HYP, // propagation hyp or local 1D hyp is missing + HAS_PROPAG_HYP, // propag hyp on this submesh + IN_CHAIN, // submesh is in propagation chain + LAST_IN_CHAIN, // submesh with local 1D hyp breaking a chain + MEANINGLESS_LAST }; // meaningless + + struct PropagationMgrData : public EventListenerData + { + bool myForward; //!< true if a curve of edge in chain is codirected with one of source edge + PropagationMgrData( SubMeshState state=WAIT_PROPAG_HYP ): EventListenerData(true) { + myType = state; myForward = true; + } + void Init() { + myType = WAIT_PROPAG_HYP; mySubMeshes.clear(); myForward = true; + } + SubMeshState State() const { + return (SubMeshState) myType; + } + void SetState(SubMeshState state) { + myType = state; + } + void SetSource(SMESH_subMesh* sm ) { + mySubMeshes.clear(); if ( sm ) mySubMeshes.push_back( sm ); + } + void AddSource(SMESH_subMesh* sm ) { + if ( sm ) mySubMeshes.push_back( sm ); + } + void SetChain(list< SMESH_subMesh* >& chain ) { + mySubMeshes.clear(); mySubMeshes.splice( mySubMeshes.end(), chain ); + } + SMESH_subMeshIteratorPtr GetChain() const; + SMESH_subMesh* GetSource() const; + }; + + //============================================================================= + /*! + * \brief return static PropagationMgr + */ + PropagationMgr* PropagationMgr::GetListener() + { + static PropagationMgr theListener; + return &theListener; + } + PropagationMgr* getListener() + { + return PropagationMgr::GetListener(); + } + //============================================================================= + /*! + * \brief return PropagationMgrData found on a submesh + */ + PropagationMgrData* findData(SMESH_subMesh* sm) + { + if ( sm ) + return static_cast< PropagationMgrData* >( sm->GetEventListenerData( getListener() )); + return 0; + } + //============================================================================= + /*! + * \brief return PropagationMgrData found on theEdge submesh + */ + PropagationMgrData* findData(SMESH_Mesh& theMesh, const TopoDS_Shape& theEdge) + { + if ( theEdge.ShapeType() == TopAbs_EDGE ) + return findData( theMesh.GetSubMeshContaining( theEdge ) ); + return 0; + } + //============================================================================= + /*! + * \brief return existing or a new PropagationMgrData + */ + PropagationMgrData* getData(SMESH_subMesh* sm) + { + PropagationMgrData* data = findData( sm ); + if ( !data && sm ) { + data = new PropagationMgrData(); + sm->SetEventListener( getListener(), data, sm ); + } + return data; + } + //============================================================================= + /*! + * \brief Returns a local 1D hypothesis used for theEdge + */ + const SMESH_Hypothesis* getLocal1DHyp (SMESH_Mesh& theMesh, + const TopoDS_Shape& theEdge) + { + static SMESH_HypoFilter hypo; + hypo.Init( hypo.HasDim( 1 )). + AndNot ( hypo.IsAlgo() ). + AndNot ( hypo.IsAssignedTo( theMesh.GetMeshDS()->ShapeToMesh() )); + return theMesh.GetHypothesis( theEdge, hypo, true ); + } + //============================================================================= + /*! + * \brief Returns a propagation hypothesis assigned to theEdge + */ + const SMESH_Hypothesis* getProagationHyp (SMESH_Mesh& theMesh, + const TopoDS_Shape& theEdge) + { + static SMESH_HypoFilter propagHypFilter + ( SMESH_HypoFilter::HasName( StdMeshers_Propagation::GetName ())); + return theMesh.GetHypothesis( theEdge, propagHypFilter, true ); + } + //================================================================================ + /*! + * \brief Return an iterator on a list of submeshes + */ + SMESH_subMeshIteratorPtr iterate( list::const_iterator from, + list::const_iterator to) + { + typedef SMESH_subMesh* TsubMesh; + typedef SMDS_SetIterator< TsubMesh, list< TsubMesh >::const_iterator > TIterator; + return SMESH_subMeshIteratorPtr ( new TIterator( from, to )); + } + //================================================================================ + /*! + * \brief Build propagation chain + * \param theMainSubMesh - the submesh with Propagation hypothesis + */ + bool buildPropagationChain ( SMESH_subMesh* theMainSubMesh ) + { + DBGMSG( "buildPropagationChain from " << theMainSubMesh->GetId() ); + const TopoDS_Shape& theMainEdge = theMainSubMesh->GetSubShape(); + if (theMainEdge.ShapeType() != TopAbs_EDGE) return true; + + SMESH_Mesh* mesh = theMainSubMesh->GetFather(); + + PropagationMgrData* chainData = getData( theMainSubMesh ); + chainData->SetState( HAS_PROPAG_HYP ); + + // Edge submeshes, to which the 1D hypothesis will be propagated from theMainEdge + list & chain = chainData->mySubMeshes; + chain.clear(); + chain.push_back( theMainSubMesh ); + + TopTools_MapOfShape checkedShapes; + checkedShapes.Add( theMainEdge ); + + list::iterator smIt = chain.begin(); + for ( ; smIt != chain.end(); ++smIt ) + { + const TopoDS_Edge& anE = TopoDS::Edge( (*smIt)->GetSubShape() ); + PropagationMgrData* data = findData( *smIt ); + if ( !data ) continue; + + // Iterate on faces, having edge + TopTools_ListIteratorOfListOfShape itA (mesh->GetAncestors(anE)); + for (; itA.More(); itA.Next()) + { + // there are objects of different type among the ancestors of edge + if ( itA.Value().ShapeType() != TopAbs_WIRE || !checkedShapes.Add( itA.Value() )) + continue; + + // Get ordered edges and find index of anE in a sequence + BRepTools_WireExplorer aWE (TopoDS::Wire(itA.Value())); + vector edges; + edges.reserve(4); + int edgeIndex = 0; + for (; aWE.More(); aWE.Next()) { + TopoDS_Edge edge = aWE.Current(); + edge.Orientation( aWE.Orientation() ); + if ( edge.IsSame( anE )) + edgeIndex = edges.size(); + edges.push_back( edge ); + } + + // Find an edge opposite to anE + TopoDS_Edge anOppE; + if ( edges.size() < 4 ) { + continue; // too few edges + } + else if ( edges.size() == 4 ) { + int oppIndex = edgeIndex + 2; + if ( oppIndex > 3 ) oppIndex -= 4; + anOppE = edges[ oppIndex ]; + } + else { + // count nb sides + TopoDS_Edge prevEdge = anE; + int nbSide = 0, eIndex = edgeIndex + 1; + for ( int i = 0; i < edges.size(); ++i, ++eIndex ) + { + if ( eIndex == edges.size() ) + eIndex = 0; + if ( !SMESH_Algo::IsContinuous( prevEdge, edges[ eIndex ])) { + nbSide++; + } + else { + // check that anE is not a part of a composite side + if ( anE.IsSame( prevEdge ) || anE.IsSame( edges[ eIndex ])) { + anOppE.Nullify(); break; + } + } + if ( nbSide == 2 ) { // opposite side + if ( !anOppE.IsNull() ) { + // composite opposite side -> stop propagation + anOppE.Nullify(); break; + } + anOppE = edges[ eIndex ]; + } + if ( nbSide == 5 ) { + anOppE.Nullify(); break; // too many sides + } + prevEdge = edges[ eIndex ]; + } + if ( anOppE.IsNull() ) + continue; + if ( nbSide != 4 ) { + DBGMSG( nbSide << " sides in wire #" << mesh->GetMeshDS()->ShapeToIndex( itA.Value() ) << " - SKIP" ); + continue; + } + } + if ( anOppE.IsNull() || !checkedShapes.Add( anOppE )) + continue; + SMESH_subMesh* oppSM = mesh->GetSubMesh( anOppE ); + PropagationMgrData* oppData = getData( oppSM ); + + // Add anOppE to aChain if ... + if ( oppData->State() == WAIT_PROPAG_HYP ) // ... anOppE is not in any chain + { + oppData->SetSource( theMainSubMesh ); + if ( !getLocal1DHyp( *mesh, anOppE )) // ... no 1d hyp on anOppE + { + oppData->myForward = data->myForward; + if ( edges[ edgeIndex ].Orientation() == anOppE.Orientation() ) + oppData->myForward = !oppData->myForward; + chain.push_back( oppSM ); + oppSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); + oppData->SetState( IN_CHAIN ); + DBGMSG( "set IN_CHAIN on " << oppSM->GetId() ); + } + else { + oppData->SetState( LAST_IN_CHAIN ); + DBGMSG( "set LAST_IN_CHAIN on " << oppSM->GetId() ); + } + } + else if ( oppData->State() == LAST_IN_CHAIN ) // anOppE breaks other chain + { + DBGMSG( "encounters LAST_IN_CHAIN on " << oppSM->GetId() ); + oppData->AddSource( theMainSubMesh ); + } + } // loop on face ancestors + } // loop on the chain + + // theMainSubMesh must not be in a chain + chain.pop_front(); + + return true; + } + //================================================================================ + /*! + * \brief Clear propagation chain + */ + bool clearPropagationChain( SMESH_subMesh* subMesh ) + { + DBGMSG( "clearPropagationChain from " << subMesh->GetId() ); + if ( PropagationMgrData* data = findData( subMesh )) + { + switch ( data->State() ) { + case IN_CHAIN: + return clearPropagationChain( data->GetSource() ); + + case HAS_PROPAG_HYP: { + SMESH_subMeshIteratorPtr smIt = data->GetChain(); + while ( smIt->more() ) { + SMESH_subMesh* sm = smIt->next(); + getData( sm )->Init(); + sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); + } + data->Init(); + break; + } + case LAST_IN_CHAIN: { + SMESH_subMeshIteratorPtr smIt = iterate( data->mySubMeshes.begin(), + data->mySubMeshes.end()); + while ( smIt->more() ) + clearPropagationChain( smIt->next() ); + data->Init(); + break; + } + default:; + } + return true; + } + return false; + } + + + //================================================================================ + /*! + * \brief Return an iterator on chain submeshes + */ + //================================================================================ + + SMESH_subMeshIteratorPtr PropagationMgrData::GetChain() const + { + switch ( State() ) { + case HAS_PROPAG_HYP: + return iterate( mySubMeshes.begin(), mySubMeshes.end() ); + case IN_CHAIN: + if ( mySubMeshes.empty() ) break; + return getData( mySubMeshes.front() )->GetChain(); + default:; + } + return iterate( mySubMeshes.end(), mySubMeshes.end() ); + } + //================================================================================ + /*! + * \brief Return a propagation source submesh + */ + //================================================================================ + + SMESH_subMesh* PropagationMgrData::GetSource() const + { + if ( myType == IN_CHAIN ) + if ( !mySubMeshes.empty() ) + return mySubMeshes.front(); + return 0; + } + + + //================================================================================ + /*! + * \brief Constructor + */ + //================================================================================ + + PropagationMgr::PropagationMgr() + : SMESH_subMeshEventListener( false ) // won't be deleted by submesh + {} + //================================================================================ + /*! + * \brief Set PropagationMgr on a submesh + */ + //================================================================================ + + void PropagationMgr::Set(SMESH_subMesh * submesh) + { + DBGMSG( "PropagationMgr::Set() on " << submesh->GetId() ); + EventListenerData* data = new PropagationMgrData(); + submesh->SetEventListener( getListener(), data, submesh ); + + const SMESH_Hypothesis * propagHyp = + getProagationHyp( *submesh->GetFather(), submesh->GetSubShape() ); + if ( propagHyp ) + getListener()->ProcessEvent( SMESH_subMesh::ADD_HYP, + SMESH_subMesh::ALGO_EVENT, + submesh, + data, + propagHyp); + } + //================================================================================ + /*! + * \brief Return an edge from which hypotheses are propagated + */ + //================================================================================ + + TopoDS_Edge PropagationMgr::GetSource(SMESH_subMesh * submesh) + { + if ( PropagationMgrData* data = findData( submesh )) { + if ( data->State() == IN_CHAIN ) { + if ( SMESH_subMesh* sm = data->GetSource() ) + { + TopoDS_Shape edge = sm->GetSubShape(); + edge = edge.Oriented( data->myForward ? TopAbs_FORWARD : TopAbs_REVERSED ); + DBGMSG( " GetSource() = edge " << sm->GetId() << " REV = " << (!data->myForward)); + if ( edge.ShapeType() == TopAbs_EDGE ) + return TopoDS::Edge( edge ); + } + } + } + return TopoDS_Edge(); + } + //================================================================================ + /*! + * \brief React on events on 1D submeshes + */ + //================================================================================ + + void PropagationMgr::ProcessEvent(const int event, + const int eventType, + SMESH_subMesh* subMesh, + SMESH_subMeshEventListenerData* listenerData, + const SMESH_Hypothesis* hyp) + { + if ( !listenerData ) + return; + if ( !hyp || hyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO || hyp->GetDim() != 1 ) + return; + if ( eventType != SMESH_subMesh::ALGO_EVENT ) + return; + DBGMSG( "PropagationMgr::ProcessEvent() on " << subMesh->GetId() ); + + bool isPropagHyp = ( StdMeshers_Propagation::GetName() == hyp->GetName() ); + + PropagationMgrData* data = static_cast( listenerData ); + switch ( data->State() ) { + + case WAIT_PROPAG_HYP: { // propagation hyp or local 1D hyp is missing + // -------------------------------------------------------- + bool hasPropagHyp = ( isPropagHyp || + getProagationHyp( *subMesh->GetFather(), subMesh->GetSubShape()) ); + if ( !hasPropagHyp ) + return; + bool hasLocal1DHyp = getLocal1DHyp( *subMesh->GetFather(), subMesh->GetSubShape()); + if ( !hasLocal1DHyp ) + return; + if ( event == SMESH_subMesh::ADD_HYP || + event == SMESH_subMesh::ADD_FATHER_HYP ) // add local or propagation hyp + { + DBGMSG( "ADD_HYP propagation to WAIT_PROPAG_HYP " << subMesh->GetId() ); + // build propagation chain + buildPropagationChain( subMesh ); + } + return; + } + case HAS_PROPAG_HYP: { // propag hyp on this submesh + // -------------------------------------------------------- + switch ( event ) { + case SMESH_subMesh::REMOVE_HYP: + case SMESH_subMesh::REMOVE_FATHER_HYP: // remove propagation hyp + if ( isPropagHyp && !getProagationHyp( *subMesh->GetFather(), subMesh->GetSubShape()) ) + { + DBGMSG( "REMOVE_HYP propagation from HAS_PROPAG_HYP " << subMesh->GetId() ); + // clear propagation chain + clearPropagationChain( subMesh ); + } + // return; -- hyp is modified any way + default: + //case SMESH_subMesh::MODIF_HYP: // hyp modif + // clear mesh in a chain + DBGMSG( "MODIF_HYP on HAS_PROPAG_HYP " << subMesh->GetId() ); + SMESH_subMeshIteratorPtr smIt = data->GetChain(); + while ( smIt->more() ) { + SMESH_subMesh* smInChain = smIt->next(); + smInChain->AlgoStateEngine( SMESH_subMesh::MODIF_HYP, + (SMESH_Hypothesis*) hyp ); + } + return; + } + return; + } + case IN_CHAIN: { // submesh is in propagation chain + // -------------------------------------------------------- + if ( event == SMESH_subMesh::ADD_HYP ) { // add local hypothesis + if ( isPropagHyp ) { // propagation hyp added + DBGMSG( "ADD_HYP propagation on IN_CHAIN " << subMesh->GetId() ); + // collision - do nothing + } + else { // 1D hyp added + // rebuild propagation chain + DBGMSG( "ADD_HYP 1D on IN_CHAIN " << subMesh->GetId() ); + SMESH_subMesh* sourceSM = data->GetSource(); + clearPropagationChain( sourceSM ); + buildPropagationChain( sourceSM ); + } + } + return; + } + case LAST_IN_CHAIN: { // submesh with local 1D hyp, breaking a chain + // -------------------------------------------------------- + if ( event == SMESH_subMesh::REMOVE_HYP ) { // remove local hyp + // rebuild propagation chain + DBGMSG( "REMOVE_HYP 1D from LAST_IN_CHAIN " << subMesh->GetId() ); + list sourceSM = data->mySubMeshes; + clearPropagationChain( subMesh ); + SMESH_subMeshIteratorPtr smIt = iterate( sourceSM.begin(), sourceSM.end()); + while ( smIt->more() ) + buildPropagationChain( smIt->next() ); + } + return; + } + } // switch by SubMeshState + } + +} // namespace