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