1 // SMESH SMESH : implementaion of SMESH idl descriptions
3 // Copyright (C) 2003 CEA
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License.
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // 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_HypoFilter.hxx"
34 #include "SMESH_Mesh.hxx"
35 #include "SMESH_subMesh.hxx"
37 #include <TopTools_MapOfShape.hxx>
38 #include <TopTools_ListIteratorOfListOfShape.hxx>
39 #include <BRepTools_WireExplorer.hxx>
42 // cout << txt << endl;
48 // =======================================================================
50 * \brief Listener managing propagation of 1D hypotheses
52 // =======================================================================
54 class PropagationMgr: public SMESH_subMeshEventListener
57 static PropagationMgr* GetListener();
59 * \brief Set listener on edge submesh
61 static void Set(SMESH_subMesh * submesh);
63 * \brief Return an edge from which hypotheses are propagated from
65 static TopoDS_Edge GetSource(SMESH_subMesh * submesh);
67 * \brief Does it's main job
69 void ProcessEvent(const int event,
71 SMESH_subMesh* subMesh,
72 SMESH_subMeshEventListenerData* data,
73 const SMESH_Hypothesis* hyp = 0);
79 //=============================================================================
81 * StdMeshers_Propagation Implementation
83 //=============================================================================
85 StdMeshers_Propagation::StdMeshers_Propagation (int hypId, int studyId, SMESH_Gen * gen)
86 : SMESH_Hypothesis(hypId, studyId, gen)
89 _param_algo_dim = -1; // 1D auxiliary
91 StdMeshers_Propagation::~StdMeshers_Propagation() {}
92 string StdMeshers_Propagation::GetName () { return "Propagation"; }
93 ostream & StdMeshers_Propagation::SaveTo (ostream & save) { return save; }
94 istream & StdMeshers_Propagation::LoadFrom (istream & load) { return load; }
95 ostream & operator << (ostream & save, StdMeshers_Propagation & hyp) { return hyp.SaveTo(save); }
96 istream & operator >> (istream & load, StdMeshers_Propagation & hyp) { return hyp.LoadFrom(load); }
97 bool StdMeshers_Propagation::SetParametersByMesh(const SMESH_Mesh*,
98 const TopoDS_Shape& ) { return false; }
99 void StdMeshers_Propagation::SetPropagationMgr(SMESH_subMesh* subMesh) { PropagationMgr::Set( subMesh ); }
101 * \brief Return an edge from which hypotheses are propagated from
103 TopoDS_Edge StdMeshers_Propagation::GetPropagationSource(SMESH_Mesh& theMesh,
104 const TopoDS_Shape& theEdge)
106 return PropagationMgr::GetSource(theMesh.GetSubMeshContaining( theEdge ));
109 //=============================================================================
110 //=============================================================================
111 // PROPAGATION MANAGEMENT
112 //=============================================================================
113 //=============================================================================
117 enum SubMeshState { WAIT_PROPAG_HYP, // propagation hyp or local 1D hyp is missing
118 HAS_PROPAG_HYP, // propag hyp on this submesh
119 IN_CHAIN, // submesh is in propagation chain
120 LAST_IN_CHAIN, // submesh with local 1D hyp breaking a chain
121 MEANINGLESS_LAST }; // meaningless
123 struct PropagationMgrData : public EventListenerData
125 bool myForward; //!< true if a curve of edge in chain is codirected with one of source edge
126 PropagationMgrData( SubMeshState state=WAIT_PROPAG_HYP ): EventListenerData(true) {
127 myType = state; myForward = true;
130 myType = WAIT_PROPAG_HYP; mySubMeshes.clear(); myForward = true;
132 SubMeshState State() const {
133 return (SubMeshState) myType;
135 void SetState(SubMeshState state) {
138 void SetSource(SMESH_subMesh* sm ) {
139 mySubMeshes.clear(); if ( sm ) mySubMeshes.push_back( sm );
141 void AddSource(SMESH_subMesh* sm ) {
142 if ( sm ) mySubMeshes.push_back( sm );
144 void SetChain(list< SMESH_subMesh* >& chain ) {
145 mySubMeshes.clear(); mySubMeshes.splice( mySubMeshes.end(), chain );
147 SMESH_subMeshIteratorPtr GetChain() const;
148 SMESH_subMesh* GetSource() const;
151 //=============================================================================
153 * \brief return static PropagationMgr
155 PropagationMgr* PropagationMgr::GetListener()
157 static PropagationMgr theListener;
160 PropagationMgr* getListener()
162 return PropagationMgr::GetListener();
164 //=============================================================================
166 * \brief return PropagationMgrData found on a submesh
168 PropagationMgrData* findData(SMESH_subMesh* sm)
171 return static_cast< PropagationMgrData* >( sm->GetEventListenerData( getListener() ));
174 //=============================================================================
176 * \brief return PropagationMgrData found on theEdge submesh
178 PropagationMgrData* findData(SMESH_Mesh& theMesh, const TopoDS_Shape& theEdge)
180 if ( theEdge.ShapeType() == TopAbs_EDGE )
181 return findData( theMesh.GetSubMeshContaining( theEdge ) );
184 //=============================================================================
186 * \brief return existing or a new PropagationMgrData
188 PropagationMgrData* getData(SMESH_subMesh* sm)
190 PropagationMgrData* data = findData( sm );
192 data = new PropagationMgrData();
193 sm->SetEventListener( getListener(), data, sm );
197 //=============================================================================
199 * \brief Returns a local 1D hypothesis used for theEdge
201 const SMESH_Hypothesis* getLocal1DHyp (SMESH_Mesh& theMesh,
202 const TopoDS_Shape& theEdge)
204 static SMESH_HypoFilter hypo;
205 hypo.Init( hypo.HasDim( 1 )).
206 AndNot ( hypo.IsAlgo() ).
207 AndNot ( hypo.IsAssignedTo( theMesh.GetMeshDS()->ShapeToMesh() ));
208 return theMesh.GetHypothesis( theEdge, hypo, true );
210 //=============================================================================
212 * \brief Returns a propagation hypothesis assigned to theEdge
214 const SMESH_Hypothesis* getProagationHyp (SMESH_Mesh& theMesh,
215 const TopoDS_Shape& theEdge)
217 static SMESH_HypoFilter propagHypFilter
218 ( SMESH_HypoFilter::HasName( StdMeshers_Propagation::GetName ()));
219 return theMesh.GetHypothesis( theEdge, propagHypFilter, true );
221 //================================================================================
223 * \brief Return an iterator on a list of submeshes
225 SMESH_subMeshIteratorPtr iterate( list<SMESH_subMesh*>::const_iterator from,
226 list<SMESH_subMesh*>::const_iterator to)
228 typedef SMESH_subMesh* TsubMesh;
229 typedef SMDS_SetIterator< TsubMesh, list< TsubMesh >::const_iterator > TIterator;
230 return SMESH_subMeshIteratorPtr ( new TIterator( from, to ));
232 //================================================================================
234 * \brief Build propagation chain
235 * \param theMainSubMesh - the submesh with Propagation hypothesis
237 bool buildPropagationChain ( SMESH_subMesh* theMainSubMesh )
239 DBGMSG( "buildPropagationChain from " << theMainSubMesh->GetId() );
240 const TopoDS_Shape& theMainEdge = theMainSubMesh->GetSubShape();
241 if (theMainEdge.ShapeType() != TopAbs_EDGE) return true;
243 SMESH_Mesh* mesh = theMainSubMesh->GetFather();
245 PropagationMgrData* chainData = getData( theMainSubMesh );
246 chainData->SetState( HAS_PROPAG_HYP );
248 // Edge submeshes, to which the 1D hypothesis will be propagated from theMainEdge
249 list<SMESH_subMesh*> & chain = chainData->mySubMeshes;
251 chain.push_back( theMainSubMesh );
253 TopTools_MapOfShape checkedShapes;
254 checkedShapes.Add( theMainEdge );
256 list<SMESH_subMesh*>::iterator smIt = chain.begin();
257 for ( ; smIt != chain.end(); ++smIt )
259 const TopoDS_Edge& anE = TopoDS::Edge( (*smIt)->GetSubShape() );
260 PropagationMgrData* data = findData( *smIt );
261 if ( !data ) continue;
263 // Iterate on faces, having edge <anE>
264 TopTools_ListIteratorOfListOfShape itA (mesh->GetAncestors(anE));
265 for (; itA.More(); itA.Next())
267 // there are objects of different type among the ancestors of edge
268 if ( itA.Value().ShapeType() != TopAbs_WIRE || !checkedShapes.Add( itA.Value() ))
271 // Get ordered edges and find index of anE in a sequence
272 BRepTools_WireExplorer aWE (TopoDS::Wire(itA.Value()));
273 vector<TopoDS_Edge> edges;
276 for (; aWE.More(); aWE.Next()) {
277 TopoDS_Edge edge = aWE.Current();
278 edge.Orientation( aWE.Orientation() );
279 if ( edge.IsSame( anE ))
280 edgeIndex = edges.size();
281 edges.push_back( edge );
284 // Find an edge opposite to anE
286 if ( edges.size() < 4 ) {
287 continue; // too few edges
289 else if ( edges.size() == 4 ) {
290 int oppIndex = edgeIndex + 2;
291 if ( oppIndex > 3 ) oppIndex -= 4;
292 anOppE = edges[ oppIndex ];
296 TopoDS_Edge prevEdge = anE;
297 int nbSide = 0, eIndex = edgeIndex + 1;
298 for ( int i = 0; i < edges.size(); ++i, ++eIndex )
300 if ( eIndex == edges.size() )
302 if ( !SMESH_Algo::IsContinuous( prevEdge, edges[ eIndex ])) {
306 // check that anE is not a part of a composite side
307 if ( anE.IsSame( prevEdge ) || anE.IsSame( edges[ eIndex ])) {
308 anOppE.Nullify(); break;
311 if ( nbSide == 2 ) { // opposite side
312 if ( !anOppE.IsNull() ) {
313 // composite opposite side -> stop propagation
314 anOppE.Nullify(); break;
316 anOppE = edges[ eIndex ];
319 anOppE.Nullify(); break; // too many sides
321 prevEdge = edges[ eIndex ];
323 if ( anOppE.IsNull() )
326 DBGMSG( nbSide << " sides in wire #" << mesh->GetMeshDS()->ShapeToIndex( itA.Value() ) << " - SKIP" );
330 if ( anOppE.IsNull() || !checkedShapes.Add( anOppE ))
332 SMESH_subMesh* oppSM = mesh->GetSubMesh( anOppE );
333 PropagationMgrData* oppData = getData( oppSM );
335 // Add anOppE to aChain if ...
336 if ( oppData->State() == WAIT_PROPAG_HYP ) // ... anOppE is not in any chain
338 oppData->SetSource( theMainSubMesh );
339 if ( !getLocal1DHyp( *mesh, anOppE )) // ... no 1d hyp on anOppE
341 oppData->myForward = data->myForward;
342 if ( edges[ edgeIndex ].Orientation() == anOppE.Orientation() )
343 oppData->myForward = !oppData->myForward;
344 chain.push_back( oppSM );
345 oppSM->ComputeStateEngine( SMESH_subMesh::CLEAN );
346 oppData->SetState( IN_CHAIN );
347 DBGMSG( "set IN_CHAIN on " << oppSM->GetId() );
350 oppData->SetState( LAST_IN_CHAIN );
351 DBGMSG( "set LAST_IN_CHAIN on " << oppSM->GetId() );
354 else if ( oppData->State() == LAST_IN_CHAIN ) // anOppE breaks other chain
356 DBGMSG( "encounters LAST_IN_CHAIN on " << oppSM->GetId() );
357 oppData->AddSource( theMainSubMesh );
359 } // loop on face ancestors
360 } // loop on the chain
362 // theMainSubMesh must not be in a chain
367 //================================================================================
369 * \brief Clear propagation chain
371 bool clearPropagationChain( SMESH_subMesh* subMesh )
373 DBGMSG( "clearPropagationChain from " << subMesh->GetId() );
374 if ( PropagationMgrData* data = findData( subMesh ))
376 switch ( data->State() ) {
378 return clearPropagationChain( data->GetSource() );
380 case HAS_PROPAG_HYP: {
381 SMESH_subMeshIteratorPtr smIt = data->GetChain();
382 while ( smIt->more() ) {
383 SMESH_subMesh* sm = smIt->next();
384 getData( sm )->Init();
385 sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
390 case LAST_IN_CHAIN: {
391 SMESH_subMeshIteratorPtr smIt = iterate( data->mySubMeshes.begin(),
392 data->mySubMeshes.end());
393 while ( smIt->more() )
394 clearPropagationChain( smIt->next() );
406 //================================================================================
408 * \brief Return an iterator on chain submeshes
410 //================================================================================
412 SMESH_subMeshIteratorPtr PropagationMgrData::GetChain() const
416 return iterate( mySubMeshes.begin(), mySubMeshes.end() );
418 if ( mySubMeshes.empty() ) break;
419 return getData( mySubMeshes.front() )->GetChain();
422 return iterate( mySubMeshes.end(), mySubMeshes.end() );
424 //================================================================================
426 * \brief Return a propagation source submesh
428 //================================================================================
430 SMESH_subMesh* PropagationMgrData::GetSource() const
432 if ( myType == IN_CHAIN )
433 if ( !mySubMeshes.empty() )
434 return mySubMeshes.front();
439 //================================================================================
443 //================================================================================
445 PropagationMgr::PropagationMgr()
446 : SMESH_subMeshEventListener( false ) // won't be deleted by submesh
448 //================================================================================
450 * \brief Set PropagationMgr on a submesh
452 //================================================================================
454 void PropagationMgr::Set(SMESH_subMesh * submesh)
456 DBGMSG( "PropagationMgr::Set() on " << submesh->GetId() );
457 EventListenerData* data = new PropagationMgrData();
458 submesh->SetEventListener( getListener(), data, submesh );
460 const SMESH_Hypothesis * propagHyp =
461 getProagationHyp( *submesh->GetFather(), submesh->GetSubShape() );
463 getListener()->ProcessEvent( SMESH_subMesh::ADD_HYP,
464 SMESH_subMesh::ALGO_EVENT,
469 //================================================================================
471 * \brief Return an edge from which hypotheses are propagated
473 //================================================================================
475 TopoDS_Edge PropagationMgr::GetSource(SMESH_subMesh * submesh)
477 if ( PropagationMgrData* data = findData( submesh )) {
478 if ( data->State() == IN_CHAIN ) {
479 if ( SMESH_subMesh* sm = data->GetSource() )
481 TopoDS_Shape edge = sm->GetSubShape();
482 edge = edge.Oriented( data->myForward ? TopAbs_FORWARD : TopAbs_REVERSED );
483 DBGMSG( " GetSource() = edge " << sm->GetId() << " REV = " << (!data->myForward));
484 if ( edge.ShapeType() == TopAbs_EDGE )
485 return TopoDS::Edge( edge );
489 return TopoDS_Edge();
491 //================================================================================
493 * \brief React on events on 1D submeshes
495 //================================================================================
497 void PropagationMgr::ProcessEvent(const int event,
499 SMESH_subMesh* subMesh,
500 SMESH_subMeshEventListenerData* listenerData,
501 const SMESH_Hypothesis* hyp)
505 if ( !hyp || hyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO || hyp->GetDim() != 1 )
507 if ( eventType != SMESH_subMesh::ALGO_EVENT )
509 DBGMSG( "PropagationMgr::ProcessEvent() on " << subMesh->GetId() );
511 bool isPropagHyp = ( StdMeshers_Propagation::GetName() == hyp->GetName() );
513 PropagationMgrData* data = static_cast<PropagationMgrData*>( listenerData );
514 switch ( data->State() ) {
516 case WAIT_PROPAG_HYP: { // propagation hyp or local 1D hyp is missing
517 // --------------------------------------------------------
518 bool hasPropagHyp = ( isPropagHyp ||
519 getProagationHyp( *subMesh->GetFather(), subMesh->GetSubShape()) );
522 bool hasLocal1DHyp = getLocal1DHyp( *subMesh->GetFather(), subMesh->GetSubShape());
523 if ( !hasLocal1DHyp )
525 if ( event == SMESH_subMesh::ADD_HYP ||
526 event == SMESH_subMesh::ADD_FATHER_HYP ) // add local or propagation hyp
528 DBGMSG( "ADD_HYP propagation to WAIT_PROPAG_HYP " << subMesh->GetId() );
529 // build propagation chain
530 buildPropagationChain( subMesh );
534 case HAS_PROPAG_HYP: { // propag hyp on this submesh
535 // --------------------------------------------------------
537 case SMESH_subMesh::REMOVE_HYP:
538 case SMESH_subMesh::REMOVE_FATHER_HYP: // remove propagation hyp
539 if ( isPropagHyp && !getProagationHyp( *subMesh->GetFather(), subMesh->GetSubShape()) )
541 DBGMSG( "REMOVE_HYP propagation from HAS_PROPAG_HYP " << subMesh->GetId() );
542 // clear propagation chain
543 clearPropagationChain( subMesh );
546 case SMESH_subMesh::MODIF_HYP: // hyp modif
547 // clear mesh in a chain
548 DBGMSG( "MODIF_HYP on HAS_PROPAG_HYP " << subMesh->GetId() );
549 SMESH_subMeshIteratorPtr smIt = data->GetChain();
550 while ( smIt->more() ) {
551 SMESH_subMesh* smInChain = smIt->next();
552 smInChain->AlgoStateEngine( SMESH_subMesh::MODIF_HYP,
553 (SMESH_Hypothesis*) hyp );
559 case IN_CHAIN: { // submesh is in propagation chain
560 // --------------------------------------------------------
561 if ( event == SMESH_subMesh::ADD_HYP ) { // add local hypothesis
562 if ( isPropagHyp ) { // propagation hyp added
563 DBGMSG( "ADD_HYP propagation on IN_CHAIN " << subMesh->GetId() );
564 // collision - do nothing
566 else { // 1D hyp added
567 // rebuild propagation chain
568 DBGMSG( "ADD_HYP 1D on IN_CHAIN " << subMesh->GetId() );
569 SMESH_subMesh* sourceSM = data->GetSource();
570 clearPropagationChain( sourceSM );
571 buildPropagationChain( sourceSM );
576 case LAST_IN_CHAIN: { // submesh with local 1D hyp, breaking a chain
577 // --------------------------------------------------------
578 if ( event == SMESH_subMesh::REMOVE_HYP ) { // remove local hyp
579 // rebuild propagation chain
580 DBGMSG( "REMOVE_HYP 1D from LAST_IN_CHAIN " << subMesh->GetId() );
581 list<SMESH_subMesh*> sourceSM = data->mySubMeshes;
582 clearPropagationChain( subMesh );
583 SMESH_subMeshIteratorPtr smIt = iterate( sourceSM.begin(), sourceSM.end());
584 while ( smIt->more() )
585 buildPropagationChain( smIt->next() );
589 } // switch by SubMeshState