Salome HOME
correct previous integration (Porting to Python 2.6)
[modules/smesh.git] / src / StdMeshers / StdMeshers_Propagation.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
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.
10 //
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.
15 //
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
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  SMESH SMESH : implementaion of SMESH idl descriptions
23 //  File   : StdMeshers_Propagation.cxx
24 //  Module : SMESH
25
26 #include "StdMeshers_Propagation.hxx"
27
28 #include "utilities.h"
29
30 #include "SMDS_SetIterator.hxx"
31 #include "SMESH_Algo.hxx"
32 #include "SMESH_HypoFilter.hxx"
33 #include "SMESH_Mesh.hxx"
34 #include "SMESH_subMesh.hxx"
35
36 #include <BRepTools_WireExplorer.hxx>
37 #include <TopTools_ListIteratorOfListOfShape.hxx>
38 #include <TopTools_MapOfShape.hxx>
39 #include <TopoDS.hxx>
40
41 #define DBGMSG(txt) \
42 //  cout << txt << endl;
43
44 using namespace std;
45
46 namespace {
47
48   // =======================================================================
49   /*!
50    * \brief Listener managing propagation of 1D hypotheses
51    */
52   // =======================================================================
53
54   class PropagationMgr: public SMESH_subMeshEventListener
55   {
56   public:
57     static PropagationMgr* GetListener();
58     /*!
59      * \brief Set listener on edge submesh
60      */
61     static void Set(SMESH_subMesh * submesh);
62     /*!
63      * \brief Return an edge from which hypotheses are propagated from
64      */
65     static TopoDS_Edge GetSource(SMESH_subMesh * submesh);
66     /*!
67      * \brief Does it's main job
68      */
69     void ProcessEvent(const int          event,
70                       const int          eventType,
71                       SMESH_subMesh*     subMesh,
72                       SMESH_subMeshEventListenerData* data,
73                       const SMESH_Hypothesis*         hyp = 0);
74   private:
75     PropagationMgr();
76   };
77 }
78
79 //=============================================================================
80 /*!
81  * StdMeshers_Propagation Implementation
82  */
83 //=============================================================================
84
85 StdMeshers_Propagation::StdMeshers_Propagation (int hypId, int studyId, SMESH_Gen * gen)
86   : SMESH_Hypothesis(hypId, studyId, gen)
87 {
88   _name = GetName();
89   _param_algo_dim = -1; // 1D auxiliary
90 }
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 bool StdMeshers_Propagation::SetParametersByDefaults(const TDefaults&,const SMESH_Mesh*) { return false; }
100 void StdMeshers_Propagation::SetPropagationMgr(SMESH_subMesh* subMesh) { PropagationMgr::Set( subMesh ); }
101 /*!
102  * \brief Return an edge from which hypotheses are propagated from
103  */
104 TopoDS_Edge StdMeshers_Propagation::GetPropagationSource(SMESH_Mesh& theMesh,
105                                                          const TopoDS_Shape& theEdge)
106 {
107   return PropagationMgr::GetSource(theMesh.GetSubMeshContaining( theEdge ));
108 }
109
110 //=============================================================================
111 //=============================================================================
112 // PROPAGATION MANAGEMENT
113 //=============================================================================
114 //=============================================================================
115
116 namespace {
117
118   enum SubMeshState { WAIT_PROPAG_HYP, // propagation hyp or local 1D hyp is missing
119                       HAS_PROPAG_HYP,  // propag hyp on this submesh
120                       IN_CHAIN,        // submesh is in propagation chain
121                       LAST_IN_CHAIN,   // submesh with local 1D hyp breaking a chain
122                       MEANINGLESS_LAST };          // meaningless
123
124   struct PropagationMgrData : public EventListenerData
125   {
126     bool myForward; //!< true if a curve of edge in chain is codirected with one of source edge
127     PropagationMgrData( SubMeshState state=WAIT_PROPAG_HYP ): EventListenerData(true) {
128       myType = state; myForward = true;
129     }
130     void Init() {
131       myType = WAIT_PROPAG_HYP;  mySubMeshes.clear(); myForward = true;
132     }
133     SubMeshState State() const {
134       return (SubMeshState) myType;
135     }
136     void SetState(SubMeshState state) {
137       myType = state;
138     }
139     void SetSource(SMESH_subMesh* sm ) {
140       mySubMeshes.clear(); if ( sm ) mySubMeshes.push_back( sm );
141     }
142     void AddSource(SMESH_subMesh* sm ) {
143       if ( sm ) mySubMeshes.push_back( sm );
144     }
145     void SetChain(list< SMESH_subMesh* >& chain ) {
146       mySubMeshes.clear(); mySubMeshes.splice( mySubMeshes.end(), chain );
147     }
148     SMESH_subMeshIteratorPtr GetChain() const;
149     SMESH_subMesh* GetSource() const;
150   };
151
152   //=============================================================================
153   /*!
154    * \brief return static PropagationMgr
155    */
156   PropagationMgr* PropagationMgr::GetListener()
157   {
158     static PropagationMgr theListener;
159     return &theListener;
160   }
161   PropagationMgr* getListener()
162   {
163     return PropagationMgr::GetListener();
164   }
165   //=============================================================================
166   /*!
167    * \brief return PropagationMgrData found on a submesh
168    */
169   PropagationMgrData* findData(SMESH_subMesh* sm)
170   {
171     if ( sm )
172       return static_cast< PropagationMgrData* >( sm->GetEventListenerData( getListener() ));
173     return 0;
174   }
175   //=============================================================================
176   /*!
177    * \brief return PropagationMgrData found on theEdge submesh
178    */
179   PropagationMgrData* findData(SMESH_Mesh& theMesh, const TopoDS_Shape& theEdge)
180   {
181     if ( theEdge.ShapeType() == TopAbs_EDGE )
182       return findData( theMesh.GetSubMeshContaining( theEdge ) );
183     return 0;
184   }
185   //=============================================================================
186   /*!
187    * \brief return existing or a new PropagationMgrData
188    */
189   PropagationMgrData* getData(SMESH_subMesh* sm)
190   {
191     PropagationMgrData* data = findData( sm );
192     if ( !data && sm ) {
193       data = new PropagationMgrData();
194       sm->SetEventListener( getListener(), data, sm );
195     }
196     return data;
197   }
198   //=============================================================================
199   /*!
200    * \brief Returns a local 1D hypothesis used for theEdge
201    */
202   const SMESH_Hypothesis* getLocal1DHyp (SMESH_Mesh&         theMesh,
203                                          const TopoDS_Shape& theEdge)
204   {
205     static SMESH_HypoFilter hypo;
206     hypo.Init( hypo.HasDim( 1 )).
207       AndNot ( hypo.IsAlgo() ).
208       AndNot ( hypo.IsAssignedTo( theMesh.GetMeshDS()->ShapeToMesh() ));
209     return theMesh.GetHypothesis( theEdge, hypo, true );
210   }
211   //=============================================================================
212   /*!
213    * \brief Returns a propagation hypothesis assigned to theEdge
214    */
215   const SMESH_Hypothesis* getProagationHyp (SMESH_Mesh&         theMesh,
216                                             const TopoDS_Shape& theEdge)
217   {
218     static SMESH_HypoFilter propagHypFilter
219       ( SMESH_HypoFilter::HasName( StdMeshers_Propagation::GetName ()));
220     return theMesh.GetHypothesis( theEdge, propagHypFilter, true );
221   }
222   //================================================================================
223   /*!
224    * \brief Return an iterator on a list of submeshes
225    */
226   SMESH_subMeshIteratorPtr iterate( list<SMESH_subMesh*>::const_iterator from,
227                                     list<SMESH_subMesh*>::const_iterator to)
228   {
229     typedef SMESH_subMesh* TsubMesh;
230     typedef SMDS_SetIterator< TsubMesh, list< TsubMesh >::const_iterator > TIterator;
231     return SMESH_subMeshIteratorPtr ( new TIterator( from, to ));
232   }
233   //================================================================================
234   /*!
235    * \brief Build propagation chain
236     * \param theMainSubMesh - the submesh with Propagation hypothesis
237    */
238   bool buildPropagationChain ( SMESH_subMesh* theMainSubMesh )
239   {
240     DBGMSG( "buildPropagationChain from " << theMainSubMesh->GetId() );
241     const TopoDS_Shape& theMainEdge = theMainSubMesh->GetSubShape();
242     if (theMainEdge.ShapeType() != TopAbs_EDGE) return true;
243
244     SMESH_Mesh* mesh = theMainSubMesh->GetFather();
245
246     PropagationMgrData* chainData = getData( theMainSubMesh );
247     chainData->SetState( HAS_PROPAG_HYP );
248
249     // Edge submeshes, to which the 1D hypothesis will be propagated from theMainEdge
250     list<SMESH_subMesh*> & chain = chainData->mySubMeshes;
251     chain.clear();
252     chain.push_back( theMainSubMesh );
253
254     TopTools_MapOfShape checkedShapes;
255     checkedShapes.Add( theMainEdge );
256
257     list<SMESH_subMesh*>::iterator smIt = chain.begin();
258     for ( ; smIt != chain.end(); ++smIt )
259     {
260       const TopoDS_Edge& anE = TopoDS::Edge( (*smIt)->GetSubShape() );
261       PropagationMgrData* data = findData( *smIt );
262       if ( !data ) continue;
263
264       // Iterate on faces, having edge <anE>
265       TopTools_ListIteratorOfListOfShape itA (mesh->GetAncestors(anE));
266       for (; itA.More(); itA.Next())
267       {
268         // there are objects of different type among the ancestors of edge
269         if ( itA.Value().ShapeType() != TopAbs_WIRE || !checkedShapes.Add( itA.Value() ))
270           continue;
271
272         // Get ordered edges and find index of anE in a sequence
273         BRepTools_WireExplorer aWE (TopoDS::Wire(itA.Value()));
274         vector<TopoDS_Edge> edges;
275         edges.reserve(4);
276         int edgeIndex = 0;
277         for (; aWE.More(); aWE.Next()) {
278           TopoDS_Edge edge = aWE.Current();
279           edge.Orientation( aWE.Orientation() );
280           if ( edge.IsSame( anE ))
281             edgeIndex = edges.size();
282           edges.push_back( edge );
283         }
284
285         // Find an edge opposite to anE
286         TopoDS_Edge anOppE;
287         if ( edges.size() < 4 ) {
288           continue; // too few edges
289         }
290         else if ( edges.size() == 4 ) {
291           int oppIndex = edgeIndex + 2;
292           if ( oppIndex > 3 ) oppIndex -= 4;
293           anOppE = edges[ oppIndex ];
294         }
295         else {
296           // count nb sides
297           TopoDS_Edge prevEdge = anE;
298           int nbSide = 0, eIndex = edgeIndex + 1;
299           for ( int i = 0; i < edges.size(); ++i, ++eIndex )
300           {
301             if ( eIndex == edges.size() )
302               eIndex = 0;
303             if ( !SMESH_Algo::IsContinuous( prevEdge, edges[ eIndex ])) {
304               nbSide++;
305             }
306             else {
307               // check that anE is not a part of a composite side
308               if ( anE.IsSame( prevEdge ) || anE.IsSame( edges[ eIndex ])) {
309                 anOppE.Nullify(); break;
310               }
311             }
312             if ( nbSide == 2 ) { // opposite side
313               if ( !anOppE.IsNull() ) {
314                 // composite opposite side -> stop propagation
315                 anOppE.Nullify(); break;
316               }
317               anOppE = edges[ eIndex ];
318             }
319             if ( nbSide == 5 ) {
320               anOppE.Nullify(); break; // too many sides
321             }
322             prevEdge = edges[ eIndex ];
323           }
324           if ( anOppE.IsNull() )
325             continue;
326           if ( nbSide != 4 ) {
327             DBGMSG( nbSide << " sides in wire #" << mesh->GetMeshDS()->ShapeToIndex( itA.Value() ) << " - SKIP" );
328             continue;
329           }
330         }
331         if ( anOppE.IsNull() || !checkedShapes.Add( anOppE ))
332           continue;
333         SMESH_subMesh* oppSM = mesh->GetSubMesh( anOppE );
334         PropagationMgrData* oppData = getData( oppSM );
335
336         // Add anOppE to aChain if ...
337         if ( oppData->State() == WAIT_PROPAG_HYP ) // ... anOppE is not in any chain
338         {
339           oppData->SetSource( theMainSubMesh );
340           if ( !getLocal1DHyp( *mesh, anOppE )) // ... no 1d hyp on anOppE
341           {
342             oppData->myForward = data->myForward;
343             if ( edges[ edgeIndex ].Orientation() == anOppE.Orientation() )
344               oppData->myForward = !oppData->myForward;
345             chain.push_back( oppSM );
346             oppSM->ComputeStateEngine( SMESH_subMesh::CLEAN );
347             oppData->SetState( IN_CHAIN );
348             DBGMSG( "set IN_CHAIN on " << oppSM->GetId() );
349           }
350           else {
351             oppData->SetState( LAST_IN_CHAIN );
352             DBGMSG( "set LAST_IN_CHAIN on " << oppSM->GetId() );
353           }
354         }
355         else if ( oppData->State() == LAST_IN_CHAIN ) // anOppE breaks other chain
356         {
357           DBGMSG( "encounters LAST_IN_CHAIN on " << oppSM->GetId() );
358           oppData->AddSource( theMainSubMesh );
359         }
360       } // loop on face ancestors
361     } // loop on the chain
362
363     // theMainSubMesh must not be in a chain
364     chain.pop_front();
365
366     return true;
367   }
368   //================================================================================
369   /*!
370    * \brief Clear propagation chain
371    */
372   bool clearPropagationChain( SMESH_subMesh* subMesh )
373   {
374     DBGMSG( "clearPropagationChain from " << subMesh->GetId() );
375     if ( PropagationMgrData* data = findData( subMesh ))
376     {
377       switch ( data->State() ) {
378       case IN_CHAIN:
379         return clearPropagationChain( data->GetSource() );
380
381       case HAS_PROPAG_HYP: {
382         SMESH_subMeshIteratorPtr smIt = data->GetChain();
383         while ( smIt->more() ) {
384           SMESH_subMesh* sm = smIt->next();
385           getData( sm )->Init();
386           sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
387         }
388         data->Init();
389         break;
390       }
391       case LAST_IN_CHAIN: {
392         SMESH_subMeshIteratorPtr smIt = iterate( data->mySubMeshes.begin(),
393                                                  data->mySubMeshes.end());
394         while ( smIt->more() )
395           clearPropagationChain( smIt->next() );
396         data->Init();
397         break;
398       }
399       default:;
400       }
401       return true;
402     }
403     return false;
404   }
405
406
407   //================================================================================
408   /*!
409    * \brief Return an iterator on chain submeshes
410    */
411   //================================================================================
412
413   SMESH_subMeshIteratorPtr PropagationMgrData::GetChain() const
414   {
415     switch ( State() ) {
416     case HAS_PROPAG_HYP:
417       return iterate( mySubMeshes.begin(), mySubMeshes.end() );
418     case IN_CHAIN:
419       if ( mySubMeshes.empty() ) break;
420       return getData( mySubMeshes.front() )->GetChain();
421     default:;
422     }
423     return iterate( mySubMeshes.end(), mySubMeshes.end() );
424   }
425   //================================================================================
426   /*!
427    * \brief Return a propagation source submesh
428    */
429   //================================================================================
430
431   SMESH_subMesh* PropagationMgrData::GetSource() const
432   {
433     if ( myType == IN_CHAIN )
434       if ( !mySubMeshes.empty() ) 
435         return mySubMeshes.front();
436     return 0;
437   }
438
439
440   //================================================================================
441   /*!
442    * \brief Constructor
443    */
444   //================================================================================
445
446   PropagationMgr::PropagationMgr()
447     : SMESH_subMeshEventListener( false ) // won't be deleted by submesh
448   {}
449   //================================================================================
450   /*!
451    * \brief Set PropagationMgr on a submesh
452    */
453   //================================================================================
454
455   void PropagationMgr::Set(SMESH_subMesh * submesh)
456   {
457     DBGMSG( "PropagationMgr::Set() on  " << submesh->GetId() );
458     EventListenerData* data = new PropagationMgrData();
459     submesh->SetEventListener( getListener(), data, submesh );
460
461     const SMESH_Hypothesis * propagHyp =
462       getProagationHyp( *submesh->GetFather(), submesh->GetSubShape() );
463     if ( propagHyp )
464       getListener()->ProcessEvent( SMESH_subMesh::ADD_HYP,
465                                    SMESH_subMesh::ALGO_EVENT,
466                                    submesh,
467                                    data,
468                                    propagHyp);
469   }
470   //================================================================================
471   /*!
472    * \brief Return an edge from which hypotheses are propagated
473    */
474   //================================================================================
475
476   TopoDS_Edge PropagationMgr::GetSource(SMESH_subMesh * submesh)
477   {
478     if ( PropagationMgrData* data = findData( submesh )) {
479       if ( data->State() == IN_CHAIN ) {
480         if ( SMESH_subMesh* sm = data->GetSource() )
481         {
482           TopoDS_Shape edge = sm->GetSubShape();
483           edge = edge.Oriented( data->myForward ? TopAbs_FORWARD : TopAbs_REVERSED );
484           DBGMSG( " GetSource() = edge " << sm->GetId() << " REV = " << (!data->myForward));
485           if ( edge.ShapeType() == TopAbs_EDGE )
486             return TopoDS::Edge( edge );
487         }
488       }
489     }
490     return TopoDS_Edge();
491   }
492   //================================================================================
493   /*!
494    * \brief React on events on 1D submeshes
495    */
496   //================================================================================
497
498   void PropagationMgr::ProcessEvent(const int          event,
499                                     const int          eventType,
500                                     SMESH_subMesh*     subMesh,
501                                     SMESH_subMeshEventListenerData* listenerData,
502                                     const SMESH_Hypothesis*         hyp)
503   {
504     if ( !listenerData )
505       return;
506     if ( !hyp || hyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO || hyp->GetDim() != 1 )
507       return;
508     if ( eventType != SMESH_subMesh::ALGO_EVENT )
509       return;
510     DBGMSG( "PropagationMgr::ProcessEvent() on  " << subMesh->GetId() );
511
512     bool isPropagHyp = ( StdMeshers_Propagation::GetName() == hyp->GetName() );
513
514     PropagationMgrData* data = static_cast<PropagationMgrData*>( listenerData );
515     switch ( data->State() ) {
516
517     case WAIT_PROPAG_HYP: { // propagation hyp or local 1D hyp is missing
518       // --------------------------------------------------------
519       bool hasPropagHyp = ( isPropagHyp ||
520                             getProagationHyp( *subMesh->GetFather(), subMesh->GetSubShape()) );
521       if ( !hasPropagHyp )
522         return;
523       bool hasLocal1DHyp =  getLocal1DHyp( *subMesh->GetFather(), subMesh->GetSubShape());
524       if ( !hasLocal1DHyp )
525         return;
526       if ( event == SMESH_subMesh::ADD_HYP ||
527            event == SMESH_subMesh::ADD_FATHER_HYP ) // add local or propagation hyp
528       {
529         DBGMSG( "ADD_HYP propagation to WAIT_PROPAG_HYP " << subMesh->GetId() );
530         // build propagation chain
531         buildPropagationChain( subMesh );
532       }
533       return;
534     }
535     case HAS_PROPAG_HYP: {  // propag hyp on this submesh
536       // --------------------------------------------------------
537       switch ( event ) {
538       case SMESH_subMesh::REMOVE_HYP:
539       case SMESH_subMesh::REMOVE_FATHER_HYP: // remove propagation hyp
540         if ( isPropagHyp && !getProagationHyp( *subMesh->GetFather(), subMesh->GetSubShape()) )
541         {
542           DBGMSG( "REMOVE_HYP propagation from HAS_PROPAG_HYP " << subMesh->GetId() );
543           // clear propagation chain
544           clearPropagationChain( subMesh );
545         }
546         // return; -- hyp is modified any way
547       default:
548         //case SMESH_subMesh::MODIF_HYP: // hyp modif
549         // clear mesh in a chain
550         DBGMSG( "MODIF_HYP on HAS_PROPAG_HYP " << subMesh->GetId() );
551         SMESH_subMeshIteratorPtr smIt = data->GetChain();
552         while ( smIt->more() ) {
553           SMESH_subMesh* smInChain = smIt->next();
554           smInChain->AlgoStateEngine( SMESH_subMesh::MODIF_HYP,
555                                       (SMESH_Hypothesis*) hyp );
556         }
557         return;
558       }
559       return;
560     }
561     case IN_CHAIN: {       // submesh is in propagation chain
562       // --------------------------------------------------------
563       if ( event == SMESH_subMesh::ADD_HYP ) { // add local hypothesis
564         if ( isPropagHyp ) { // propagation hyp added
565           DBGMSG( "ADD_HYP propagation on IN_CHAIN " << subMesh->GetId() );
566           // collision - do nothing
567         }
568         else { // 1D hyp added
569           // rebuild propagation chain
570           DBGMSG( "ADD_HYP 1D on IN_CHAIN " << subMesh->GetId() );
571           SMESH_subMesh* sourceSM = data->GetSource();
572           clearPropagationChain( sourceSM );
573           buildPropagationChain( sourceSM );
574         }
575       }
576       return;
577     }
578     case LAST_IN_CHAIN: { // submesh with local 1D hyp, breaking a chain
579       // --------------------------------------------------------
580       if ( event == SMESH_subMesh::REMOVE_HYP ) { // remove local hyp
581         // rebuild propagation chain
582         DBGMSG( "REMOVE_HYP 1D from LAST_IN_CHAIN " << subMesh->GetId() );
583         list<SMESH_subMesh*> sourceSM = data->mySubMeshes;
584         clearPropagationChain( subMesh );
585         SMESH_subMeshIteratorPtr smIt = iterate( sourceSM.begin(), sourceSM.end());
586         while ( smIt->more() )
587           buildPropagationChain( smIt->next() );
588       }
589       return;
590     }
591     } // switch by SubMeshState
592   }
593
594 } // namespace