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