1 // Copyright (C) 2007-2013 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SMESH SMESH : implementaion of SMESH idl descriptions
24 // File : StdMeshers_Propagation.cxx
27 #include "StdMeshers_Propagation.hxx"
29 #include "utilities.h"
31 #include "SMDS_SetIterator.hxx"
32 #include "SMESH_Algo.hxx"
33 #include "SMESH_Gen.hxx"
34 #include "SMESH_HypoFilter.hxx"
35 #include "SMESH_Mesh.hxx"
36 #include "SMESH_subMesh.hxx"
38 #include <BRepTools_WireExplorer.hxx>
39 #include <TopTools_ListIteratorOfListOfShape.hxx>
40 #include <TopTools_MapOfShape.hxx>
44 // cout << txt << endl;
50 // =======================================================================
52 * \brief Listener managing propagation of 1D hypotheses
54 // =======================================================================
56 class PropagationMgr: public SMESH_subMeshEventListener
59 static PropagationMgr* GetListener();
61 * \brief Set listener on edge submesh
63 static void Set(SMESH_subMesh * submesh);
65 * \brief Return an edge from which hypotheses are propagated from
67 static TopoDS_Edge GetSource(SMESH_subMesh * submesh);
69 * \brief Does it's main job
71 void ProcessEvent(const int event,
73 SMESH_subMesh* subMesh,
74 SMESH_subMeshEventListenerData* data,
75 const SMESH_Hypothesis* hyp = 0);
81 //=============================================================================
83 * StdMeshers_Propagation Implementation
85 //=============================================================================
87 StdMeshers_Propagation::StdMeshers_Propagation (int hypId, int studyId, SMESH_Gen * gen)
88 : SMESH_Hypothesis(hypId, studyId, gen)
91 _param_algo_dim = -1; // 1D auxiliary
93 StdMeshers_Propagation::~StdMeshers_Propagation() {}
94 string StdMeshers_Propagation::GetName () { return "Propagation"; }
95 ostream & StdMeshers_Propagation::SaveTo (ostream & save) { return save; }
96 istream & StdMeshers_Propagation::LoadFrom (istream & load) { return load; }
97 ostream & operator << (ostream & save, StdMeshers_Propagation & hyp) { return hyp.SaveTo(save); }
98 istream & operator >> (istream & load, StdMeshers_Propagation & hyp) { return hyp.LoadFrom(load); }
99 bool StdMeshers_Propagation::SetParametersByMesh(const SMESH_Mesh*,
100 const TopoDS_Shape& ) { return false; }
101 bool StdMeshers_Propagation::SetParametersByDefaults(const TDefaults&,const SMESH_Mesh*) { return false; }
102 void StdMeshers_Propagation::SetPropagationMgr(SMESH_subMesh* subMesh) { PropagationMgr::Set( subMesh ); }
104 * \brief Return an edge from which hypotheses are propagated from
106 TopoDS_Edge StdMeshers_Propagation::GetPropagationSource(SMESH_Mesh& theMesh,
107 const TopoDS_Shape& theEdge)
109 return PropagationMgr::GetSource(theMesh.GetSubMeshContaining( theEdge ));
112 //=============================================================================
113 //=============================================================================
114 // PROPAGATION MANAGEMENT
115 //=============================================================================
116 //=============================================================================
120 enum SubMeshState { WAIT_PROPAG_HYP, // propagation hyp or local 1D hyp is missing
121 HAS_PROPAG_HYP, // propag hyp on this submesh
122 IN_CHAIN, // submesh is in propagation chain
123 LAST_IN_CHAIN, // submesh with local 1D hyp breaking a chain
124 MEANINGLESS_LAST }; // meaningless
126 struct PropagationMgrData : public EventListenerData
128 bool myForward; //!< true if a curve of edge in chain is codirected with one of source edge
129 PropagationMgrData( SubMeshState state=WAIT_PROPAG_HYP ): EventListenerData(true) {
130 myType = state; myForward = true;
133 myType = WAIT_PROPAG_HYP; mySubMeshes.clear(); myForward = true;
135 SubMeshState State() const {
136 return (SubMeshState) myType;
138 void SetState(SubMeshState state) {
141 void SetSource(SMESH_subMesh* sm ) {
142 mySubMeshes.clear(); if ( sm ) mySubMeshes.push_back( sm );
144 void AddSource(SMESH_subMesh* sm ) {
145 if ( sm ) mySubMeshes.push_back( sm );
147 void SetChain(list< SMESH_subMesh* >& chain ) {
148 mySubMeshes.clear(); mySubMeshes.splice( mySubMeshes.end(), chain );
150 SMESH_subMeshIteratorPtr GetChain() const;
151 SMESH_subMesh* GetSource() const;
154 //=============================================================================
156 * \brief return static PropagationMgr
158 PropagationMgr* PropagationMgr::GetListener()
160 static PropagationMgr theListener;
163 PropagationMgr* getListener()
165 return PropagationMgr::GetListener();
167 //=============================================================================
169 * \brief return PropagationMgrData found on a submesh
171 PropagationMgrData* findData(SMESH_subMesh* sm)
174 return static_cast< PropagationMgrData* >( sm->GetEventListenerData( getListener() ));
177 //=============================================================================
179 * \brief return PropagationMgrData found on theEdge submesh
181 PropagationMgrData* findData(SMESH_Mesh& theMesh, const TopoDS_Shape& theEdge)
183 if ( theEdge.ShapeType() == TopAbs_EDGE )
184 return findData( theMesh.GetSubMeshContaining( theEdge ) );
187 //=============================================================================
189 * \brief return existing or a new PropagationMgrData
191 PropagationMgrData* getData(SMESH_subMesh* sm)
193 PropagationMgrData* data = findData( sm );
195 data = new PropagationMgrData();
196 sm->SetEventListener( getListener(), data, sm );
200 //=============================================================================
202 * \brief Returns a local 1D hypothesis used for theEdge
204 const SMESH_Hypothesis* getLocal1DHyp (SMESH_Mesh& theMesh,
205 const TopoDS_Shape& theEdge)
207 static SMESH_HypoFilter hypo;
208 hypo.Init( hypo.HasDim( 1 )).
209 AndNot ( hypo.IsAlgo() ).
210 AndNot ( hypo.IsAssignedTo( theMesh.GetMeshDS()->ShapeToMesh() ));
211 return theMesh.GetHypothesis( theEdge, hypo, true );
213 //=============================================================================
215 * \brief Returns a propagation hypothesis assigned to theEdge
217 const SMESH_Hypothesis* getProagationHyp (SMESH_Mesh& theMesh,
218 const TopoDS_Shape& theEdge)
220 static SMESH_HypoFilter propagHypFilter
221 ( SMESH_HypoFilter::HasName( StdMeshers_Propagation::GetName ()));
222 return theMesh.GetHypothesis( theEdge, propagHypFilter, true );
224 //================================================================================
226 * \brief Return an iterator on a list of submeshes
228 SMESH_subMeshIteratorPtr iterate( list<SMESH_subMesh*>::const_iterator from,
229 list<SMESH_subMesh*>::const_iterator to)
231 typedef SMESH_subMesh* TsubMesh;
232 typedef SMDS_SetIterator< TsubMesh, list< TsubMesh >::const_iterator > TIterator;
233 return SMESH_subMeshIteratorPtr ( new TIterator( from, to ));
235 //================================================================================
237 * \brief Build propagation chain
238 * \param theMainSubMesh - the submesh with Propagation hypothesis
240 bool buildPropagationChain ( SMESH_subMesh* theMainSubMesh )
242 DBGMSG( "buildPropagationChain from " << theMainSubMesh->GetId() );
243 const TopoDS_Shape& theMainEdge = theMainSubMesh->GetSubShape();
244 if (theMainEdge.ShapeType() != TopAbs_EDGE) return true;
246 SMESH_Mesh* mesh = theMainSubMesh->GetFather();
248 PropagationMgrData* chainData = getData( theMainSubMesh );
249 chainData->SetState( HAS_PROPAG_HYP );
251 // Edge submeshes, to which the 1D hypothesis will be propagated from theMainEdge
252 list<SMESH_subMesh*> & chain = chainData->mySubMeshes;
254 chain.push_back( theMainSubMesh );
256 TopTools_MapOfShape checkedShapes;
257 checkedShapes.Add( theMainEdge );
259 list<SMESH_subMesh*>::iterator smIt = chain.begin();
260 for ( ; smIt != chain.end(); ++smIt )
262 const TopoDS_Edge& anE = TopoDS::Edge( (*smIt)->GetSubShape() );
263 PropagationMgrData* data = findData( *smIt );
264 if ( !data ) continue;
266 // Iterate on faces, having edge <anE>
267 TopTools_ListIteratorOfListOfShape itA (mesh->GetAncestors(anE));
268 for (; itA.More(); itA.Next())
270 // there are objects of different type among the ancestors of edge
271 if ( itA.Value().ShapeType() != TopAbs_WIRE /*|| !checkedShapes.Add( itA.Value() )*/)
274 // Get ordered edges and find index of anE in a sequence
275 BRepTools_WireExplorer aWE (TopoDS::Wire(itA.Value()));
276 vector<TopoDS_Edge> edges;
279 for (; aWE.More(); aWE.Next()) {
280 TopoDS_Edge edge = aWE.Current();
281 edge.Orientation( aWE.Orientation() );
282 if ( edge.IsSame( anE ))
283 edgeIndex = edges.size();
284 edges.push_back( edge );
287 // Find an edge opposite to anE
289 if ( edges.size() < 4 ) {
290 continue; // too few edges
292 else if ( edges.size() == 4 ) {
293 int oppIndex = ( edgeIndex + 2 ) % 4;
294 anOppE = edges[ oppIndex ];
298 TopoDS_Edge prevEdge = anE;
299 int nbSide = 0, eIndex = edgeIndex + 1;
300 for ( int i = 0; i < edges.size(); ++i, ++eIndex )
302 if ( eIndex == edges.size() )
304 if ( !SMESH_Algo::IsContinuous( prevEdge, edges[ eIndex ])) {
308 // check that anE is not a part of a composite side
309 if ( anE.IsSame( prevEdge ) || anE.IsSame( edges[ eIndex ])) {
310 anOppE.Nullify(); break;
313 if ( nbSide == 2 ) { // opposite side
314 if ( !anOppE.IsNull() ) {
315 // composite opposite side -> stop propagation
316 anOppE.Nullify(); break;
318 anOppE = edges[ eIndex ];
321 anOppE.Nullify(); break; // too many sides
323 prevEdge = edges[ eIndex ];
325 if ( anOppE.IsNull() )
328 DBGMSG( nbSide << " sides in wire #" << mesh->GetMeshDS()->ShapeToIndex( itA.Value() ) << " - SKIP" );
332 if ( anOppE.IsNull() || !checkedShapes.Add( anOppE ))
334 SMESH_subMesh* oppSM = mesh->GetSubMesh( anOppE );
335 PropagationMgrData* oppData = getData( oppSM );
337 // Add anOppE to aChain if ...
338 if ( oppData->State() == WAIT_PROPAG_HYP ) // ... anOppE is not in any chain
340 oppData->SetSource( theMainSubMesh );
341 if ( !getLocal1DHyp( *mesh, anOppE )) // ... no 1d hyp on anOppE
343 oppData->myForward = data->myForward;
344 if ( edges[ edgeIndex ].Orientation() == anOppE.Orientation() )
345 oppData->myForward = !oppData->myForward;
346 chain.push_back( oppSM );
347 oppSM->ComputeStateEngine( SMESH_subMesh::CLEAN );
348 oppData->SetState( IN_CHAIN );
349 DBGMSG( "set IN_CHAIN on " << oppSM->GetId() );
350 if ( oppSM->GetAlgoState() != SMESH_subMesh::HYP_OK )
351 // make oppSM check algo state
352 if ( SMESH_Algo* algo = mesh->GetGen()->GetAlgo( *mesh, anOppE ))
353 oppSM->AlgoStateEngine(SMESH_subMesh::ADD_FATHER_ALGO,algo);
356 oppData->SetState( LAST_IN_CHAIN );
357 DBGMSG( "set LAST_IN_CHAIN on " << oppSM->GetId() );
360 else if ( oppData->State() == LAST_IN_CHAIN ) // anOppE breaks other chain
362 DBGMSG( "encounters LAST_IN_CHAIN on " << oppSM->GetId() );
363 oppData->AddSource( theMainSubMesh );
365 } // loop on face ancestors
366 } // loop on the chain
368 // theMainSubMesh must not be in a chain
373 //================================================================================
375 * \brief Clear propagation chain
377 bool clearPropagationChain( SMESH_subMesh* subMesh )
379 DBGMSG( "clearPropagationChain from " << subMesh->GetId() );
380 if ( PropagationMgrData* data = findData( subMesh ))
382 switch ( data->State() ) {
384 return clearPropagationChain( data->GetSource() );
386 case HAS_PROPAG_HYP: {
387 SMESH_subMeshIteratorPtr smIt = data->GetChain();
388 while ( smIt->more() ) {
389 SMESH_subMesh* sm = smIt->next();
390 getData( sm )->Init();
391 sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
396 case LAST_IN_CHAIN: {
397 SMESH_subMeshIteratorPtr smIt = iterate( data->mySubMeshes.begin(),
398 data->mySubMeshes.end());
399 while ( smIt->more() )
400 clearPropagationChain( smIt->next() );
412 //================================================================================
414 * \brief Return an iterator on chain submeshes
416 //================================================================================
418 SMESH_subMeshIteratorPtr PropagationMgrData::GetChain() const
422 return iterate( mySubMeshes.begin(), mySubMeshes.end() );
424 if ( mySubMeshes.empty() ) break;
425 return getData( mySubMeshes.front() )->GetChain();
428 return iterate( mySubMeshes.end(), mySubMeshes.end() );
430 //================================================================================
432 * \brief Return a propagation source submesh
434 //================================================================================
436 SMESH_subMesh* PropagationMgrData::GetSource() const
438 if ( myType == IN_CHAIN )
439 if ( !mySubMeshes.empty() )
440 return mySubMeshes.front();
445 //================================================================================
449 //================================================================================
451 PropagationMgr::PropagationMgr()
452 : SMESH_subMeshEventListener( false, // won't be deleted by submesh
453 "StdMeshers_Propagation::PropagationMgr")
455 //================================================================================
457 * \brief Set PropagationMgr on a submesh
459 //================================================================================
461 void PropagationMgr::Set(SMESH_subMesh * submesh)
463 if ( findData( submesh )) return;
464 DBGMSG( "PropagationMgr::Set() on " << submesh->GetId() );
465 EventListenerData* data = new PropagationMgrData();
466 submesh->SetEventListener( getListener(), data, submesh );
468 const SMESH_Hypothesis * propagHyp =
469 getProagationHyp( *submesh->GetFather(), submesh->GetSubShape() );
471 getListener()->ProcessEvent( SMESH_subMesh::ADD_HYP,
472 SMESH_subMesh::ALGO_EVENT,
477 //================================================================================
479 * \brief Return an edge from which hypotheses are propagated
481 //================================================================================
483 TopoDS_Edge PropagationMgr::GetSource(SMESH_subMesh * submesh)
485 if ( PropagationMgrData* data = findData( submesh )) {
486 if ( data->State() == IN_CHAIN ) {
487 if ( SMESH_subMesh* sm = data->GetSource() )
489 TopoDS_Shape edge = sm->GetSubShape();
490 edge = edge.Oriented( data->myForward ? TopAbs_FORWARD : TopAbs_REVERSED );
491 DBGMSG( " GetSource() = edge " << sm->GetId() << " REV = " << (!data->myForward));
492 if ( edge.ShapeType() == TopAbs_EDGE )
493 return TopoDS::Edge( edge );
497 return TopoDS_Edge();
499 //================================================================================
501 * \brief React on events on 1D submeshes
503 //================================================================================
505 void PropagationMgr::ProcessEvent(const int event,
507 SMESH_subMesh* subMesh,
508 SMESH_subMeshEventListenerData* listenerData,
509 const SMESH_Hypothesis* hyp)
513 if ( !hyp || hyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO || hyp->GetDim() != 1 )
515 if ( eventType != SMESH_subMesh::ALGO_EVENT )
517 DBGMSG( "PropagationMgr::ProcessEvent() on " << subMesh->GetId() );
519 bool isPropagHyp = ( StdMeshers_Propagation::GetName() == hyp->GetName() );
521 PropagationMgrData* data = static_cast<PropagationMgrData*>( listenerData );
522 switch ( data->State() ) {
524 case WAIT_PROPAG_HYP: { // propagation hyp or local 1D hyp is missing
525 // --------------------------------------------------------
526 bool hasPropagHyp = ( isPropagHyp ||
527 getProagationHyp( *subMesh->GetFather(), subMesh->GetSubShape()) );
530 bool hasLocal1DHyp = getLocal1DHyp( *subMesh->GetFather(), subMesh->GetSubShape());
531 if ( !hasLocal1DHyp )
533 if ( event == SMESH_subMesh::ADD_HYP ||
534 event == SMESH_subMesh::ADD_FATHER_HYP ) // add local or propagation hyp
536 DBGMSG( "ADD_HYP propagation to WAIT_PROPAG_HYP " << subMesh->GetId() );
537 // build propagation chain
538 buildPropagationChain( subMesh );
542 case HAS_PROPAG_HYP: { // propag hyp on this submesh
543 // --------------------------------------------------------
545 case SMESH_subMesh::REMOVE_HYP:
546 case SMESH_subMesh::REMOVE_FATHER_HYP: // remove propagation hyp
547 if ( isPropagHyp && !getProagationHyp( *subMesh->GetFather(), subMesh->GetSubShape()) )
549 DBGMSG( "REMOVE_HYP propagation from HAS_PROPAG_HYP " << subMesh->GetId() );
550 // clear propagation chain
551 clearPropagationChain( subMesh );
553 // return; -- hyp is modified any way
555 //case SMESH_subMesh::MODIF_HYP: // hyp modif
556 // clear mesh in a chain
557 DBGMSG( "MODIF_HYP on HAS_PROPAG_HYP " << subMesh->GetId() );
558 SMESH_subMeshIteratorPtr smIt = data->GetChain();
559 while ( smIt->more() ) {
560 SMESH_subMesh* smInChain = smIt->next();
561 smInChain->AlgoStateEngine( SMESH_subMesh::MODIF_HYP,
562 (SMESH_Hypothesis*) hyp );
568 case IN_CHAIN: { // submesh is in propagation chain
569 // --------------------------------------------------------
570 if ( event == SMESH_subMesh::ADD_HYP ) { // add local hypothesis
571 if ( isPropagHyp ) { // propagation hyp added
572 DBGMSG( "ADD_HYP propagation on IN_CHAIN " << subMesh->GetId() );
573 // collision - do nothing
575 else { // 1D hyp added
576 // rebuild propagation chain
577 DBGMSG( "ADD_HYP 1D on IN_CHAIN " << subMesh->GetId() );
578 SMESH_subMesh* sourceSM = data->GetSource();
579 clearPropagationChain( sourceSM );
580 buildPropagationChain( sourceSM );
585 case LAST_IN_CHAIN: { // submesh with local 1D hyp, breaking a chain
586 // --------------------------------------------------------
587 if ( event == SMESH_subMesh::REMOVE_HYP ) { // remove local hyp
588 // rebuild propagation chain
589 DBGMSG( "REMOVE_HYP 1D from LAST_IN_CHAIN " << subMesh->GetId() );
590 list<SMESH_subMesh*> sourceSM = data->mySubMeshes;
591 clearPropagationChain( subMesh );
592 SMESH_subMeshIteratorPtr smIt = iterate( sourceSM.begin(), sourceSM.end());
593 while ( smIt->more() )
594 buildPropagationChain( smIt->next() );
598 } // switch by SubMeshState