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