Salome HOME
Join modifications from V3_2_0_maintainance (V3_2_6pre4 - T32x_16Aug2007_16h00m)
[modules/smesh.git] / src / StdMeshers / StdMeshers_Propagation.cxx
1 //  SMESH SMESH : implementaion of SMESH idl descriptions
2 //
3 //  Copyright (C) 2003  CEA
4 //
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.
9 //
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.
14 //
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
18 //
19 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 //
21 //
22 //
23 //  File   : StdMeshers_Propagation.cxx
24 //  Module : SMESH
25 //  $Header$
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 <TopTools_MapOfShape.hxx>
38 #include <TopTools_ListIteratorOfListOfShape.hxx>
39 #include <BRepTools_WireExplorer.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 void StdMeshers_Propagation::SetPropagationMgr(SMESH_subMesh* subMesh) { PropagationMgr::Set( subMesh ); }
100 /*!
101  * \brief Return an edge from which hypotheses are propagated from
102  */
103 TopoDS_Edge StdMeshers_Propagation::GetPropagationSource(SMESH_Mesh& theMesh,
104                                                          const TopoDS_Shape& theEdge)
105 {
106   return PropagationMgr::GetSource(theMesh.GetSubMeshContaining( theEdge ));
107 }
108
109 //=============================================================================
110 //=============================================================================
111 // PROPAGATION MANAGEMENT
112 //=============================================================================
113 //=============================================================================
114
115 namespace {
116
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
122
123   struct PropagationMgrData : public EventListenerData
124   {
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;
128     }
129     void Init() {
130       myType = WAIT_PROPAG_HYP;  mySubMeshes.clear(); myForward = true;
131     }
132     SubMeshState State() const {
133       return (SubMeshState) myType;
134     }
135     void SetState(SubMeshState state) {
136       myType = state;
137     }
138     void SetSource(SMESH_subMesh* sm ) {
139       mySubMeshes.clear(); if ( sm ) mySubMeshes.push_back( sm );
140     }
141     void AddSource(SMESH_subMesh* sm ) {
142       if ( sm ) mySubMeshes.push_back( sm );
143     }
144     void SetChain(list< SMESH_subMesh* >& chain ) {
145       mySubMeshes.clear(); mySubMeshes.splice( mySubMeshes.end(), chain );
146     }
147     SMESH_subMeshIteratorPtr GetChain() const;
148     SMESH_subMesh* GetSource() const;
149   };
150
151   //=============================================================================
152   /*!
153    * \brief return static PropagationMgr
154    */
155   PropagationMgr* PropagationMgr::GetListener()
156   {
157     static PropagationMgr theListener;
158     return &theListener;
159   }
160   PropagationMgr* getListener()
161   {
162     return PropagationMgr::GetListener();
163   }
164   //=============================================================================
165   /*!
166    * \brief return PropagationMgrData found on a submesh
167    */
168   PropagationMgrData* findData(SMESH_subMesh* sm)
169   {
170     if ( sm )
171       return static_cast< PropagationMgrData* >( sm->GetEventListenerData( getListener() ));
172     return 0;
173   }
174   //=============================================================================
175   /*!
176    * \brief return PropagationMgrData found on theEdge submesh
177    */
178   PropagationMgrData* findData(SMESH_Mesh& theMesh, const TopoDS_Shape& theEdge)
179   {
180     if ( theEdge.ShapeType() == TopAbs_EDGE )
181       return findData( theMesh.GetSubMeshContaining( theEdge ) );
182     return 0;
183   }
184   //=============================================================================
185   /*!
186    * \brief return existing or a new PropagationMgrData
187    */
188   PropagationMgrData* getData(SMESH_subMesh* sm)
189   {
190     PropagationMgrData* data = findData( sm );
191     if ( !data && sm ) {
192       data = new PropagationMgrData();
193       sm->SetEventListener( getListener(), data, sm );
194     }
195     return data;
196   }
197   //=============================================================================
198   /*!
199    * \brief Returns a local 1D hypothesis used for theEdge
200    */
201   const SMESH_Hypothesis* getLocal1DHyp (SMESH_Mesh&         theMesh,
202                                          const TopoDS_Shape& theEdge)
203   {
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 );
209   }
210   //=============================================================================
211   /*!
212    * \brief Returns a propagation hypothesis assigned to theEdge
213    */
214   const SMESH_Hypothesis* getProagationHyp (SMESH_Mesh&         theMesh,
215                                             const TopoDS_Shape& theEdge)
216   {
217     static SMESH_HypoFilter propagHypFilter
218       ( SMESH_HypoFilter::HasName( StdMeshers_Propagation::GetName ()));
219     return theMesh.GetHypothesis( theEdge, propagHypFilter, true );
220   }
221   //================================================================================
222   /*!
223    * \brief Return an iterator on a list of submeshes
224    */
225   SMESH_subMeshIteratorPtr iterate( list<SMESH_subMesh*>::const_iterator from,
226                                     list<SMESH_subMesh*>::const_iterator to)
227   {
228     typedef SMESH_subMesh* TsubMesh;
229     typedef SMDS_SetIterator< TsubMesh, list< TsubMesh >::const_iterator > TIterator;
230     return SMESH_subMeshIteratorPtr ( new TIterator( from, to ));
231   }
232   //================================================================================
233   /*!
234    * \brief Build propagation chain
235     * \param theMainSubMesh - the submesh with Propagation hypothesis
236    */
237   bool buildPropagationChain ( SMESH_subMesh* theMainSubMesh )
238   {
239     DBGMSG( "buildPropagationChain from " << theMainSubMesh->GetId() );
240     const TopoDS_Shape& theMainEdge = theMainSubMesh->GetSubShape();
241     if (theMainEdge.ShapeType() != TopAbs_EDGE) return true;
242
243     SMESH_Mesh* mesh = theMainSubMesh->GetFather();
244
245     PropagationMgrData* chainData = getData( theMainSubMesh );
246     chainData->SetState( HAS_PROPAG_HYP );
247
248     // Edge submeshes, to which the 1D hypothesis will be propagated from theMainEdge
249     list<SMESH_subMesh*> & chain = chainData->mySubMeshes;
250     chain.clear();
251     chain.push_back( theMainSubMesh );
252
253     TopTools_MapOfShape checkedShapes;
254     checkedShapes.Add( theMainEdge );
255
256     list<SMESH_subMesh*>::iterator smIt = chain.begin();
257     for ( ; smIt != chain.end(); ++smIt )
258     {
259       const TopoDS_Edge& anE = TopoDS::Edge( (*smIt)->GetSubShape() );
260       PropagationMgrData* data = findData( *smIt );
261       if ( !data ) continue;
262
263       // Iterate on faces, having edge <anE>
264       TopTools_ListIteratorOfListOfShape itA (mesh->GetAncestors(anE));
265       for (; itA.More(); itA.Next())
266       {
267         // there are objects of different type among the ancestors of edge
268         if ( itA.Value().ShapeType() != TopAbs_WIRE || !checkedShapes.Add( itA.Value() ))
269           continue;
270
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;
274         edges.reserve(4);
275         int edgeIndex = 0;
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 );
282         }
283
284         // Find an edge opposite to anE
285         TopoDS_Edge anOppE;
286         if ( edges.size() < 4 ) {
287           continue; // too few edges
288         }
289         else if ( edges.size() == 4 ) {
290           int oppIndex = edgeIndex + 2;
291           if ( oppIndex > 3 ) oppIndex -= 4;
292           anOppE = edges[ oppIndex ];
293         }
294         else {
295           // count nb sides
296           TopoDS_Edge prevEdge = anE;
297           int nbSide = 0, eIndex = edgeIndex + 1;
298           for ( int i = 0; i < edges.size(); ++i, ++eIndex )
299           {
300             if ( eIndex == edges.size() )
301               eIndex = 0;
302             if ( !SMESH_Algo::IsContinuous( prevEdge, edges[ eIndex ])) {
303               nbSide++;
304             }
305             else {
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;
309               }
310             }
311             if ( nbSide == 2 ) { // opposite side
312               if ( !anOppE.IsNull() ) {
313                 // composite opposite side -> stop propagation
314                 anOppE.Nullify(); break;
315               }
316               anOppE = edges[ eIndex ];
317             }
318             if ( nbSide == 5 ) {
319               anOppE.Nullify(); break; // too many sides
320             }
321             prevEdge = edges[ eIndex ];
322           }
323           if ( anOppE.IsNull() )
324             continue;
325           if ( nbSide != 4 ) {
326             DBGMSG( nbSide << " sides in wire #" << mesh->GetMeshDS()->ShapeToIndex( itA.Value() ) << " - SKIP" );
327             continue;
328           }
329         }
330         if ( anOppE.IsNull() || !checkedShapes.Add( anOppE ))
331           continue;
332         SMESH_subMesh* oppSM = mesh->GetSubMesh( anOppE );
333         PropagationMgrData* oppData = getData( oppSM );
334
335         // Add anOppE to aChain if ...
336         if ( oppData->State() == WAIT_PROPAG_HYP ) // ... anOppE is not in any chain
337         {
338           oppData->SetSource( theMainSubMesh );
339           if ( !getLocal1DHyp( *mesh, anOppE )) // ... no 1d hyp on anOppE
340           {
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() );
348           }
349           else {
350             oppData->SetState( LAST_IN_CHAIN );
351             DBGMSG( "set LAST_IN_CHAIN on " << oppSM->GetId() );
352           }
353         }
354         else if ( oppData->State() == LAST_IN_CHAIN ) // anOppE breaks other chain
355         {
356           DBGMSG( "encounters LAST_IN_CHAIN on " << oppSM->GetId() );
357           oppData->AddSource( theMainSubMesh );
358         }
359       } // loop on face ancestors
360     } // loop on the chain
361
362     // theMainSubMesh must not be in a chain
363     chain.pop_front();
364
365     return true;
366   }
367   //================================================================================
368   /*!
369    * \brief Clear propagation chain
370    */
371   bool clearPropagationChain( SMESH_subMesh* subMesh )
372   {
373     DBGMSG( "clearPropagationChain from " << subMesh->GetId() );
374     if ( PropagationMgrData* data = findData( subMesh ))
375     {
376       switch ( data->State() ) {
377       case IN_CHAIN:
378         return clearPropagationChain( data->GetSource() );
379
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 );
386         }
387         data->Init();
388         break;
389       }
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() );
395         data->Init();
396         break;
397       }
398       default:;
399       }
400       return true;
401     }
402     return false;
403   }
404
405
406   //================================================================================
407   /*!
408    * \brief Return an iterator on chain submeshes
409    */
410   //================================================================================
411
412   SMESH_subMeshIteratorPtr PropagationMgrData::GetChain() const
413   {
414     switch ( State() ) {
415     case HAS_PROPAG_HYP:
416       return iterate( mySubMeshes.begin(), mySubMeshes.end() );
417     case IN_CHAIN:
418       if ( mySubMeshes.empty() ) break;
419       return getData( mySubMeshes.front() )->GetChain();
420     default:;
421     }
422     return iterate( mySubMeshes.end(), mySubMeshes.end() );
423   }
424   //================================================================================
425   /*!
426    * \brief Return a propagation source submesh
427    */
428   //================================================================================
429
430   SMESH_subMesh* PropagationMgrData::GetSource() const
431   {
432     if ( myType == IN_CHAIN )
433       if ( !mySubMeshes.empty() ) 
434         return mySubMeshes.front();
435     return 0;
436   }
437
438
439   //================================================================================
440   /*!
441    * \brief Constructor
442    */
443   //================================================================================
444
445   PropagationMgr::PropagationMgr()
446     : SMESH_subMeshEventListener( false ) // won't be deleted by submesh
447   {}
448   //================================================================================
449   /*!
450    * \brief Set PropagationMgr on a submesh
451    */
452   //================================================================================
453
454   void PropagationMgr::Set(SMESH_subMesh * submesh)
455   {
456     DBGMSG( "PropagationMgr::Set() on  " << submesh->GetId() );
457     EventListenerData* data = new PropagationMgrData();
458     submesh->SetEventListener( getListener(), data, submesh );
459
460     const SMESH_Hypothesis * propagHyp =
461       getProagationHyp( *submesh->GetFather(), submesh->GetSubShape() );
462     if ( propagHyp )
463       getListener()->ProcessEvent( SMESH_subMesh::ADD_HYP,
464                                    SMESH_subMesh::ALGO_EVENT,
465                                    submesh,
466                                    data,
467                                    propagHyp);
468   }
469   //================================================================================
470   /*!
471    * \brief Return an edge from which hypotheses are propagated
472    */
473   //================================================================================
474
475   TopoDS_Edge PropagationMgr::GetSource(SMESH_subMesh * submesh)
476   {
477     if ( PropagationMgrData* data = findData( submesh )) {
478       if ( data->State() == IN_CHAIN ) {
479         if ( SMESH_subMesh* sm = data->GetSource() )
480         {
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 );
486         }
487       }
488     }
489     return TopoDS_Edge();
490   }
491   //================================================================================
492   /*!
493    * \brief React on events on 1D submeshes
494    */
495   //================================================================================
496
497   void PropagationMgr::ProcessEvent(const int          event,
498                                     const int          eventType,
499                                     SMESH_subMesh*     subMesh,
500                                     SMESH_subMeshEventListenerData* listenerData,
501                                     const SMESH_Hypothesis*         hyp)
502   {
503     if ( !listenerData )
504       return;
505     if ( !hyp || hyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO || hyp->GetDim() != 1 )
506       return;
507     if ( eventType != SMESH_subMesh::ALGO_EVENT )
508       return;
509     DBGMSG( "PropagationMgr::ProcessEvent() on  " << subMesh->GetId() );
510
511     bool isPropagHyp = ( StdMeshers_Propagation::GetName() == hyp->GetName() );
512
513     PropagationMgrData* data = static_cast<PropagationMgrData*>( listenerData );
514     switch ( data->State() ) {
515
516     case WAIT_PROPAG_HYP: { // propagation hyp or local 1D hyp is missing
517       // --------------------------------------------------------
518       bool hasPropagHyp = ( isPropagHyp ||
519                             getProagationHyp( *subMesh->GetFather(), subMesh->GetSubShape()) );
520       if ( !hasPropagHyp )
521         return;
522       bool hasLocal1DHyp =  getLocal1DHyp( *subMesh->GetFather(), subMesh->GetSubShape());
523       if ( !hasLocal1DHyp )
524         return;
525       if ( event == SMESH_subMesh::ADD_HYP ||
526            event == SMESH_subMesh::ADD_FATHER_HYP ) // add local or propagation hyp
527       {
528         DBGMSG( "ADD_HYP propagation to WAIT_PROPAG_HYP " << subMesh->GetId() );
529         // build propagation chain
530         buildPropagationChain( subMesh );
531       }
532       return;
533     }
534     case HAS_PROPAG_HYP: {  // propag hyp on this submesh
535       // --------------------------------------------------------
536       switch ( event ) {
537       case SMESH_subMesh::REMOVE_HYP:
538       case SMESH_subMesh::REMOVE_FATHER_HYP: // remove propagation hyp
539         if ( isPropagHyp && !getProagationHyp( *subMesh->GetFather(), subMesh->GetSubShape()) )
540         {
541           DBGMSG( "REMOVE_HYP propagation from HAS_PROPAG_HYP " << subMesh->GetId() );
542           // clear propagation chain
543           clearPropagationChain( subMesh );
544         }
545         return;
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 );
554         }
555         return;
556       }
557       return;
558     }
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
565         }
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 );
572         }
573       }
574       return;
575     }
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() );
586       }
587       return;
588     }
589     } // switch by SubMeshState
590   }
591
592 } // namespace