Salome HOME
Merging with WPdev
[modules/smesh.git] / src / SMESH / SMESH_subMesh.cxx
1 //  SMESH SMESH : implementaion of SMESH idl descriptions
2 //
3 //  Copyright (C) 2003  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 //
24 //  File   : SMESH_subMesh.cxx
25 //  Author : Paul RASCLE, EDF
26 //  Module : SMESH
27 //  $Header$
28
29 #include "SMESH_subMesh.hxx"
30
31 #include "SMESH_subMeshEventListener.hxx"
32 #include "SMESH_Gen.hxx"
33 #include "SMESH_Mesh.hxx"
34 #include "SMESH_Hypothesis.hxx"
35 #include "SMESH_Algo.hxx"
36 #include "SMESH_HypoFilter.hxx"
37
38 #include "utilities.h"
39 #include "OpUtil.hxx"
40
41 #include <BRep_Builder.hxx>
42
43 #include <TopExp.hxx>
44 #include <TopoDS_Compound.hxx>
45 #include <TopTools_MapOfShape.hxx>
46 #include <TopTools_ListOfShape.hxx>
47 #include <TopTools_ListIteratorOfListOfShape.hxx>
48 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
49
50 #ifdef _DEBUG_
51 #include <gp_Pnt.hxx>
52 #include <BRep_Tool.hxx>
53 #include <TopoDS.hxx>
54 #include <TopTools_IndexedMapOfShape.hxx>
55 #endif
56
57 #include <Standard_Failure.hxx>
58 #include <Standard_ErrorHandler.hxx>
59
60 //=============================================================================
61 /*!
62  *  default constructor:
63  */
64 //=============================================================================
65
66 SMESH_subMesh::SMESH_subMesh(int Id, SMESH_Mesh * father, SMESHDS_Mesh * meshDS,
67         const TopoDS_Shape & aSubShape)
68 {
69         _subShape = aSubShape;
70         _meshDS = meshDS;
71         _subMeshDS = meshDS->MeshElements(_subShape);   // may be null ...
72         _father = father;
73         _Id = Id;
74         _dependenceAnalysed = false;
75
76         if (_subShape.ShapeType() == TopAbs_VERTEX)
77         {
78                 _algoState = HYP_OK;
79                 _computeState = READY_TO_COMPUTE;
80         }
81         else
82         {
83           _algoState = NO_ALGO;
84           _computeState = NOT_READY;
85         }
86 }
87
88 //=============================================================================
89 /*!
90  *
91  */
92 //=============================================================================
93
94 SMESH_subMesh::~SMESH_subMesh()
95 {
96   MESSAGE("SMESH_subMesh::~SMESH_subMesh");
97   // ****
98 }
99
100 //=============================================================================
101 /*!
102  *
103  */
104 //=============================================================================
105
106 int SMESH_subMesh::GetId() const
107 {
108   //MESSAGE("SMESH_subMesh::GetId");
109   return _Id;
110 }
111
112 //=============================================================================
113 /*!
114  *
115  */
116 //=============================================================================
117
118 SMESHDS_SubMesh * SMESH_subMesh::GetSubMeshDS()
119 {
120   // submesh appears in DS only when a mesher set nodes and elements on it
121   if (_subMeshDS==NULL)
122   {
123     _subMeshDS = _meshDS->MeshElements(_subShape);      // may be null ...
124 //     if (_subMeshDS==NULL)
125 //     {
126 //       MESSAGE("problem... subMesh still empty");
127 //     }
128   }
129   return _subMeshDS;
130 }
131
132 //=============================================================================
133 /*!
134  *
135  */
136 //=============================================================================
137
138 SMESHDS_SubMesh* SMESH_subMesh::CreateSubMeshDS()
139 {
140   if ( !GetSubMeshDS() )
141     _meshDS->NewSubMesh( _meshDS->ShapeToIndex( _subShape ) );
142
143   return GetSubMeshDS();
144 }
145
146 //=============================================================================
147 /*!
148  *
149  */
150 //=============================================================================
151
152 SMESH_subMesh *SMESH_subMesh::GetFirstToCompute()
153 {
154   const map < int, SMESH_subMesh * >&subMeshes = DependsOn();
155   SMESH_subMesh *firstToCompute = 0;
156
157   map < int, SMESH_subMesh * >::const_iterator itsub;
158   for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++)
159   {
160     SMESH_subMesh *sm = (*itsub).second;
161     bool readyToCompute = (sm->GetComputeState() == READY_TO_COMPUTE);
162     if (readyToCompute)
163     {
164       firstToCompute = sm;
165       break;
166     }
167   }
168   if (firstToCompute)
169   {
170     return firstToCompute;      // a subMesh of this
171   }
172   if (_computeState == READY_TO_COMPUTE)
173   {
174     return this;                // this
175   }
176   return 0;                     // nothing to compute
177 }
178
179 //=============================================================================
180 /*!
181  *
182  */
183 //=============================================================================
184
185 bool SMESH_subMesh::SubMeshesComputed()
186 {
187   //MESSAGE("SMESH_subMesh::SubMeshesComputed");
188   const map < int, SMESH_subMesh * >&subMeshes = DependsOn();
189
190   int myDim = SMESH_Gen::GetShapeDim( _subShape );
191   int dimToCheck = myDim - 1;
192   bool subMeshesComputed = true;
193   map < int, SMESH_subMesh * >::const_iterator itsub;
194   for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++)
195   {
196     SMESH_subMesh *sm = (*itsub).second;
197     const TopoDS_Shape & ss = sm->GetSubShape();
198     // MSV 07.04.2006: restrict checking to myDim-1 only. Ex., there is no sense
199     // in checking of existence of edges if the algo needs only faces. Moreover,
200     // degenerated edges may have no submesh, as after computing NETGEN_2D.
201     int dim = SMESH_Gen::GetShapeDim( ss );
202     if (dim < dimToCheck)
203       continue;
204     SMESHDS_SubMesh * ds = sm->GetSubMeshDS();
205     // PAL10974.
206     // There are some tricks with compute states, e.g. Penta_3D leaves
207     // one face with READY_TO_COMPUTE state in order to be able to
208     // recompute 3D when a locale triangle hypo changes (see PAL7428).
209     // So we check if mesh is really present
210     bool computeOk = (sm->GetComputeState() == COMPUTE_OK ||
211                       (ds && ( ds->GetNodes()->more() || ds->GetElements()->more() )));
212     if (!computeOk)
213     {
214       int type = ss.ShapeType();
215
216       subMeshesComputed = false;
217
218       switch (type)
219       {
220       case TopAbs_COMPOUND:
221         {
222           MESSAGE("The not computed sub mesh is a COMPOUND");
223           break;
224         }
225       case TopAbs_COMPSOLID:
226         {
227           MESSAGE("The not computed sub mesh is a COMPSOLID");
228           break;
229         }
230       case TopAbs_SHELL:
231         {
232           MESSAGE("The not computed sub mesh is a SHEL");
233           break;
234         }
235       case TopAbs_WIRE:
236         {
237           MESSAGE("The not computed sub mesh is a WIRE");
238           break;
239         }
240       case TopAbs_SOLID:
241         {
242           MESSAGE("The not computed sub mesh is a SOLID");
243           break;
244         }
245       case TopAbs_FACE:
246         {
247           MESSAGE("The not computed sub mesh is a FACE");
248           break;
249         }
250       case TopAbs_EDGE:
251         {
252           MESSAGE("The not computed sub mesh is a EDGE");
253           break;
254         }
255       default:
256         {
257           MESSAGE("The not computed sub mesh is of unknown type");
258           break;
259         }
260       }
261
262       break;
263     }
264   }
265   return subMeshesComputed;
266 }
267
268 //=============================================================================
269 /*!
270  *
271  */
272 //=============================================================================
273
274 bool SMESH_subMesh::SubMeshesReady()
275 {
276   MESSAGE("SMESH_subMesh::SubMeshesReady");
277   const map < int, SMESH_subMesh * >&subMeshes = DependsOn();
278
279   bool subMeshesReady = true;
280   map < int, SMESH_subMesh * >::const_iterator itsub;
281   for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++)
282   {
283     SMESH_subMesh *sm = (*itsub).second;
284     bool computeOk = ((sm->GetComputeState() == COMPUTE_OK)
285                       || (sm->GetComputeState() == READY_TO_COMPUTE));
286     if (!computeOk)
287     {
288       subMeshesReady = false;
289       SCRUTE(sm->GetId());
290       break;
291     }
292   }
293   return subMeshesReady;
294 }
295
296 //=============================================================================
297 /*!
298  * Construct dependence on first level subMeshes. complex shapes (compsolid,
299  * shell, wire) are not analysed the same way as simple shapes (solid, face,
300  * edge).
301  * For collection shapes (compsolid, shell, wire) prepare a list of submeshes
302  * with possible multiples occurences. Multiples occurences corresponds to
303  * internal frontiers within shapes of the collection and must not be keeped.
304  * See FinalizeDependence.
305  */
306 //=============================================================================
307
308 const map < int, SMESH_subMesh * >&SMESH_subMesh::DependsOn()
309 {
310   if (_dependenceAnalysed)
311     return _mapDepend;
312
313   //MESSAGE("SMESH_subMesh::DependsOn");
314
315   int type = _subShape.ShapeType();
316   //SCRUTE(type);
317   switch (type)
318   {
319   case TopAbs_COMPOUND:
320     {
321       //MESSAGE("compound");
322       for (TopExp_Explorer exp(_subShape, TopAbs_SOLID); exp.More();
323            exp.Next())
324       {
325         InsertDependence(exp.Current());
326       }
327       for (TopExp_Explorer exp(_subShape, TopAbs_SHELL, TopAbs_SOLID); exp.More();
328            exp.Next())
329       {
330           InsertDependence(exp.Current());      //only shell not in solid
331       }
332       for (TopExp_Explorer exp(_subShape, TopAbs_FACE, TopAbs_SHELL); exp.More();
333            exp.Next())
334       {
335         InsertDependence(exp.Current());
336       }
337       for (TopExp_Explorer exp(_subShape, TopAbs_EDGE, TopAbs_FACE); exp.More();
338            exp.Next())
339       {
340         InsertDependence(exp.Current());
341       }
342       break;
343     }
344   case TopAbs_COMPSOLID:
345     {
346                 //MESSAGE("compsolid");
347       for (TopExp_Explorer exp(_subShape, TopAbs_SOLID); exp.More();
348            exp.Next())
349       {
350         InsertDependence(exp.Current());
351       }
352       break;
353     }
354   case TopAbs_SHELL:
355     {
356       //MESSAGE("shell");
357       for (TopExp_Explorer exp(_subShape, TopAbs_FACE); exp.More();
358            exp.Next())
359       {
360         InsertDependence(exp.Current());
361       }
362       break;
363     }
364   case TopAbs_WIRE:
365     {
366       //MESSAGE("wire");
367       for (TopExp_Explorer exp(_subShape, TopAbs_EDGE); exp.More();
368            exp.Next())
369       {
370         InsertDependence(exp.Current());
371       }
372       break;
373     }
374   case TopAbs_SOLID:
375     {
376       //MESSAGE("solid");
377       for (TopExp_Explorer exp(_subShape, TopAbs_FACE); exp.More();
378            exp.Next())
379       {
380         InsertDependence(exp.Current());
381       }
382       break;
383     }
384   case TopAbs_FACE:
385     {
386       //MESSAGE("face");
387       for (TopExp_Explorer exp(_subShape, TopAbs_EDGE); exp.More();
388            exp.Next())
389       {
390         InsertDependence(exp.Current());
391       }
392       break;
393     }
394   case TopAbs_EDGE:
395     {
396       //MESSAGE("edge");
397       for (TopExp_Explorer exp(_subShape, TopAbs_VERTEX); exp.More();
398            exp.Next())
399       {
400                         InsertDependence(exp.Current());
401                       }
402       break;
403     }
404   case TopAbs_VERTEX:
405     {
406       break;
407     }
408   default:
409     {
410       break;
411     }
412   }
413   _dependenceAnalysed = true;
414   return _mapDepend;
415 }
416
417 //=============================================================================
418 /*!
419  * For simple Shapes (solid, face, edge): add subMesh into dependence list.
420  */
421 //=============================================================================
422
423 void SMESH_subMesh::InsertDependence(const TopoDS_Shape aSubShape)
424 {
425   //MESSAGE("SMESH_subMesh::InsertDependence");
426   SMESH_subMesh *aSubMesh = _father->GetSubMesh(aSubShape);
427   int type = aSubShape.ShapeType();
428   int ordType = 9 - type;               // 2 = Vertex, 8 = CompSolid
429   int cle = aSubMesh->GetId();
430   cle += 10000000 * ordType;    // sort map by ordType then index
431   if ( _mapDepend.find( cle ) == _mapDepend.end())
432   {
433     _mapDepend[cle] = aSubMesh;
434     const map < int, SMESH_subMesh * > & subMap = aSubMesh->DependsOn();
435     _mapDepend.insert( subMap.begin(), subMap.end() );
436   }
437 }
438
439 //=============================================================================
440 /*!
441  *
442  */
443 //=============================================================================
444
445 const TopoDS_Shape & SMESH_subMesh::GetSubShape() const
446 {
447         //MESSAGE("SMESH_subMesh::GetSubShape");
448         return _subShape;
449 }
450
451
452 //=======================================================================
453 //function : CanAddHypothesis
454 //purpose  : return true if theHypothesis can be attached to me:
455 //           its dimention is checked
456 //=======================================================================
457
458 bool SMESH_subMesh::CanAddHypothesis(const SMESH_Hypothesis* theHypothesis) const
459 {
460   int aHypDim   = theHypothesis->GetDim();
461   int aShapeDim = SMESH_Gen::GetShapeDim(_subShape);
462   if ( aHypDim <= aShapeDim )
463     return true;
464 //   if ( aHypDim < aShapeDim )
465 //     return ( _father->IsMainShape( _subShape ));
466
467   return false;
468 }
469
470 //=======================================================================
471 //function : IsApplicableHypotesis
472 //purpose  :
473 //=======================================================================
474
475 bool SMESH_subMesh::IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis,
476                                           const TopAbs_ShapeEnum  theShapeType)
477 {
478   if ( theHypothesis->GetType() > SMESHDS_Hypothesis::PARAM_ALGO)
479     // algorithm
480     return ( theHypothesis->GetShapeType() & (1<< theShapeType));
481
482   // hypothesis
483   switch ( theShapeType ) {
484   case TopAbs_EDGE:
485   case TopAbs_FACE:
486   case TopAbs_SOLID:
487     return SMESH_Gen::GetShapeDim( theShapeType ) == theHypothesis->GetDim();
488
489   case TopAbs_SHELL:
490     // Special case for algorithms, building 2D mesh on a whole shell.
491     // Before this fix there was a problem after restoring from study,
492     // because in that case algorithm is assigned before hypothesis
493     // (on shell in problem case) and hypothesis is checked on faces
494     // (because it is 2D), where we have NO_ALGO state.
495     // Now 2D hypothesis is also applicable to shells.
496     return (theHypothesis->GetDim() == 2 || theHypothesis->GetDim() == 3);
497
498 //   case TopAbs_WIRE:
499 //   case TopAbs_COMPSOLID:
500 //   case TopAbs_COMPOUND:
501   default:;
502   }
503   return false;
504 }
505
506 //=============================================================================
507 /*!
508  *
509  */
510 //=============================================================================
511
512 SMESH_Hypothesis::Hypothesis_Status
513   SMESH_subMesh::AlgoStateEngine(int event, SMESH_Hypothesis * anHyp)
514 {
515   //  MESSAGE("SMESH_subMesh::AlgoStateEngine");
516   //SCRUTE(_algoState);
517   //SCRUTE(event);
518
519   // **** les retour des evenement shape sont significatifs
520   // (add ou remove fait ou non)
521   // le retour des evenement father n'indiquent pas que add ou remove fait
522
523   SMESH_Hypothesis::Hypothesis_Status aux_ret, ret = SMESH_Hypothesis::HYP_OK;
524
525   int dim = SMESH_Gen::GetShapeDim(_subShape);
526
527   if (dim < 1)
528   {
529     _algoState = HYP_OK;
530     if (event == ADD_HYP || event == ADD_ALGO)
531       return SMESH_Hypothesis::HYP_BAD_DIM; // do not allow to assign any hyp
532     else
533       return SMESH_Hypothesis::HYP_OK;
534   }
535
536   SMESH_Gen* gen   =_father->GetGen();
537   SMESH_Algo* algo = 0;
538   int oldAlgoState = _algoState;
539   bool modifiedHyp = false;  // if set to true, force event MODIF_ALGO_STATE
540                              // in ComputeStateEngine
541
542   // ----------------------
543   // check mesh conformity
544   // ----------------------
545   if (event == ADD_ALGO)
546   {
547     if (IsApplicableHypotesis( anHyp ) &&
548         !_father->IsNotConformAllowed() &&
549         !IsConform( static_cast< SMESH_Algo* >( anHyp )))
550       return SMESH_Hypothesis::HYP_NOTCONFORM;
551   }
552
553   // ----------------------------------
554   // add a hypothesis to DS if possible
555   // ----------------------------------
556   if (event == ADD_HYP || event == ADD_ALGO)
557   {
558     if ( ! CanAddHypothesis( anHyp ))
559       return SMESH_Hypothesis::HYP_BAD_DIM;
560
561     if ( /*!anHyp->IsAuxiliary() &&*/ GetSimilarAttached( _subShape, anHyp ) )
562       return SMESH_Hypothesis::HYP_ALREADY_EXIST;
563
564     if ( !_meshDS->AddHypothesis(_subShape, anHyp))
565       return SMESH_Hypothesis::HYP_ALREADY_EXIST;
566
567     // Serve Propagation of 1D hypothesis
568     if (event == ADD_HYP) {
569       bool isPropagationOk = true;
570       bool isPropagationHyp = ( strcmp( "Propagation", anHyp->GetName() ) == 0 );
571
572       if ( isPropagationHyp ) {
573         TopExp_Explorer exp (_subShape, TopAbs_EDGE);
574         TopTools_MapOfShape aMap;
575         for (; exp.More(); exp.Next()) {
576           if (aMap.Add(exp.Current())) {
577             if (!_father->BuildPropagationChain(exp.Current())) {
578               isPropagationOk = false;
579             }
580           }
581         }
582       }
583       else if (anHyp->GetDim() == 1) { // Only 1D hypothesis can be propagated
584         TopExp_Explorer exp (_subShape, TopAbs_EDGE);
585         TopTools_MapOfShape aMap;
586         for (; exp.More(); exp.Next()) {
587           if (aMap.Add(exp.Current())) {
588             TopoDS_Shape aMainEdge;
589             if (_father->IsPropagatedHypothesis(exp.Current(), aMainEdge)) {
590               isPropagationOk = _father->RebuildPropagationChains();
591             } else if (_father->IsPropagationHypothesis(exp.Current())) {
592               isPropagationOk = _father->BuildPropagationChain(exp.Current());
593             } else {
594             }
595           }
596         }
597       } else {
598       }
599
600       if ( isPropagationOk ) {
601         if ( isPropagationHyp )
602           return ret; // nothing more to do for "Propagation" hypothesis
603       }
604       else if ( ret < SMESH_Hypothesis::HYP_CONCURENT) {
605         ret = SMESH_Hypothesis::HYP_CONCURENT;
606       }
607     } // Serve Propagation of 1D hypothesis
608   }
609
610   // --------------------------
611   // remove a hypothesis from DS
612   // --------------------------
613   if (event == REMOVE_HYP || event == REMOVE_ALGO)
614   {
615     if (!_meshDS->RemoveHypothesis(_subShape, anHyp))
616       return SMESH_Hypothesis::HYP_OK; // nothing changes
617
618     // Serve Propagation of 1D hypothesis
619     if (event == REMOVE_HYP)
620     {
621       bool isPropagationOk = true;
622       SMESH_HypoFilter propagFilter( SMESH_HypoFilter::HasName( "Propagation" ));
623       bool isPropagationHyp = propagFilter.IsOk( anHyp, _subShape );
624
625       if ( isPropagationHyp )
626       {
627         TopExp_Explorer exp (_subShape, TopAbs_EDGE);
628         TopTools_MapOfShape aMap;
629         for (; exp.More(); exp.Next()) {
630           if (aMap.Add(exp.Current()) &&
631               !_father->GetHypothesis( exp.Current(), propagFilter, true )) {
632             // no more Propagation on the current edge
633             if (!_father->RemovePropagationChain(exp.Current())) {
634               return SMESH_Hypothesis::HYP_UNKNOWN_FATAL;
635             }
636           }
637         }
638         // rebuild propagation chains, because removing one
639         // chain can resolve concurention, existing before
640         isPropagationOk = _father->RebuildPropagationChains();
641       }
642       else if (anHyp->GetDim() == 1) // Only 1D hypothesis can be propagated
643       {
644         isPropagationOk = _father->RebuildPropagationChains();
645       }
646
647       if ( isPropagationOk ) {
648         if ( isPropagationHyp )
649           return ret; // nothing more to do for "Propagation" hypothesis
650       }
651       else if ( ret < SMESH_Hypothesis::HYP_CONCURENT) {
652         ret = SMESH_Hypothesis::HYP_CONCURENT;
653       }
654     } // Serve Propagation of 1D hypothesis
655     else // event == REMOVE_ALGO
656     {
657       algo = dynamic_cast<SMESH_Algo*> (anHyp);
658       if (!algo->NeedDescretBoundary())
659       {
660         // clean all mesh in the tree of the current submesh;
661         // we must perform it now because later
662         // we will have no information about the type of the removed algo
663         CleanDependants();
664         ComputeStateEngine( CLEAN );
665         CleanDependsOn();
666       }
667     }
668   }
669
670   // ------------------
671   // analyse algo state
672   // ------------------
673   if (!IsApplicableHypotesis( anHyp ))
674     return ret; // not applicable hypotheses do not change algo state
675
676   switch (_algoState)
677   {
678
679     // ----------------------------------------------------------------------
680
681   case NO_ALGO:
682     switch (event) {
683     case ADD_HYP:
684       break;
685     case ADD_ALGO: {
686       algo = gen->GetAlgo((*_father), _subShape);
687       ASSERT(algo);
688       if (algo->CheckHypothesis((*_father),_subShape, aux_ret))
689         SetAlgoState(HYP_OK);
690       else if ( algo->IsStatusFatal( aux_ret )) {
691         _meshDS->RemoveHypothesis(_subShape, anHyp);
692         ret = aux_ret;
693       }
694       else
695         SetAlgoState(MISSING_HYP);
696       break;
697     }
698     case REMOVE_HYP:
699       break;
700     case REMOVE_ALGO:
701       break;
702     case ADD_FATHER_HYP:
703       break;
704     case ADD_FATHER_ALGO: {    // Algo just added in father
705       algo = gen->GetAlgo((*_father), _subShape);
706       ASSERT(algo);
707       if ( algo == anHyp ) {
708         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret))
709           SetAlgoState(HYP_OK);
710         else
711           SetAlgoState(MISSING_HYP);
712       }
713       break;
714     }
715     case REMOVE_FATHER_HYP:
716       break;
717     case REMOVE_FATHER_ALGO: {
718       algo = gen->GetAlgo((*_father), _subShape);
719       if (algo)
720       {
721         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
722             SetAlgoState(HYP_OK);
723         else
724           SetAlgoState(MISSING_HYP);
725       }
726       break;
727     }
728     default:
729       ASSERT(0);
730       break;
731     }
732     break;
733
734     // ----------------------------------------------------------------------
735
736   case MISSING_HYP:
737     switch (event)
738     {
739     case ADD_HYP: {
740       algo = gen->GetAlgo((*_father), _subShape);
741       ASSERT(algo);
742       if ( algo->CheckHypothesis((*_father),_subShape, ret ))
743         SetAlgoState(HYP_OK);
744       if (SMESH_Hypothesis::IsStatusFatal( ret ))
745         _meshDS->RemoveHypothesis(_subShape, anHyp);
746       else if (!_father->IsUsedHypothesis( anHyp, this ))
747       {
748         _meshDS->RemoveHypothesis(_subShape, anHyp);
749         ret = SMESH_Hypothesis::HYP_INCOMPATIBLE;
750       }
751       break;
752     }
753     case ADD_ALGO: {           //already existing algo : on father ?
754       algo = gen->GetAlgo((*_father), _subShape);
755       ASSERT(algo);
756       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))// ignore hyp status
757         SetAlgoState(HYP_OK);
758       else if ( algo->IsStatusFatal( aux_ret )) {
759         _meshDS->RemoveHypothesis(_subShape, anHyp);
760         ret = aux_ret;
761       }
762       else
763         SetAlgoState(MISSING_HYP);
764       break;
765     }
766     case REMOVE_HYP:
767       break;
768     case REMOVE_ALGO: {        // perhaps a father algo applies ?
769       algo = gen->GetAlgo((*_father), _subShape);
770       if (algo == NULL)  // no more algo applying on subShape...
771       {
772         SetAlgoState(NO_ALGO);
773       }
774       else
775       {
776         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
777           SetAlgoState(HYP_OK);
778         else
779           SetAlgoState(MISSING_HYP);
780       }
781       break;
782     }
783     case ADD_FATHER_HYP: {
784       algo = gen->GetAlgo((*_father), _subShape);
785       ASSERT(algo);
786       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
787         SetAlgoState(HYP_OK);
788       else
789         SetAlgoState(MISSING_HYP);
790       break;
791     }
792     case ADD_FATHER_ALGO: { // new father algo
793       algo = gen->GetAlgo((*_father), _subShape);
794       ASSERT( algo );
795       if ( algo == anHyp ) {
796         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
797           SetAlgoState(HYP_OK);
798         else
799           SetAlgoState(MISSING_HYP);
800       }
801       break;
802     }
803     case REMOVE_FATHER_HYP:    // nothing to do
804       break;
805     case REMOVE_FATHER_ALGO: {
806       algo = gen->GetAlgo((*_father), _subShape);
807       if (algo == NULL)  // no more applying algo on father
808       {
809         SetAlgoState(NO_ALGO);
810       }
811       else
812       {
813         if ( algo->CheckHypothesis((*_father),_subShape , aux_ret ))
814           SetAlgoState(HYP_OK);
815         else
816           SetAlgoState(MISSING_HYP);
817       }
818       break;
819     }
820     default:
821       ASSERT(0);
822       break;
823     }
824     break;
825
826     // ----------------------------------------------------------------------
827
828   case HYP_OK:
829     switch (event)
830     {
831     case ADD_HYP: {
832       algo = gen->GetAlgo((*_father), _subShape);
833       ASSERT(algo);
834       if (!algo->CheckHypothesis((*_father),_subShape, ret ))
835       {
836         if ( !SMESH_Hypothesis::IsStatusFatal( ret ))
837           // ret should be fatal: anHyp was not added
838           ret = SMESH_Hypothesis::HYP_INCOMPATIBLE;
839       }
840       else if (!_father->IsUsedHypothesis(  anHyp, this ))
841         ret = SMESH_Hypothesis::HYP_INCOMPATIBLE;
842
843       if (SMESH_Hypothesis::IsStatusFatal( ret ))
844       {
845         MESSAGE("do not add extra hypothesis");
846         _meshDS->RemoveHypothesis(_subShape, anHyp);
847       }
848       else
849       {
850         modifiedHyp = true;
851       }
852       break;
853     }
854     case ADD_ALGO: {           //already existing algo : on father ?
855       algo = gen->GetAlgo((*_father), _subShape);
856       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
857         // check if algo changes
858         SMESH_HypoFilter f;
859         f.Init(   SMESH_HypoFilter::IsAlgo() );
860         f.And(    SMESH_HypoFilter::IsApplicableTo( _subShape ));
861         f.AndNot( SMESH_HypoFilter::Is( algo ));
862         const SMESH_Hypothesis * prevAlgo = _father->GetHypothesis( _subShape, f, true );
863         if (prevAlgo &&
864             string(algo->GetName()) != string(prevAlgo->GetName()) )
865           modifiedHyp = true;
866       }
867       else
868         SetAlgoState(MISSING_HYP);
869       break;
870     }
871     case REMOVE_HYP: {
872       algo = gen->GetAlgo((*_father), _subShape);
873       ASSERT(algo);
874       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
875         SetAlgoState(HYP_OK);
876       else
877         SetAlgoState(MISSING_HYP);
878       modifiedHyp = true;
879       break;
880     }
881     case REMOVE_ALGO: {         // perhaps a father algo applies ?
882       algo = gen->GetAlgo((*_father), _subShape);
883       if (algo == NULL)   // no more algo applying on subShape...
884       {
885         SetAlgoState(NO_ALGO);
886       }
887       else
888       {
889         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
890           // check if algo remains
891           if ( anHyp != algo && strcmp( anHyp->GetName(), algo->GetName()) )
892             modifiedHyp = true;
893         }
894         else
895           SetAlgoState(MISSING_HYP);
896       }
897       break;
898     }
899     case ADD_FATHER_HYP: {  // new father hypothesis ?
900       algo = gen->GetAlgo((*_father), _subShape);
901       ASSERT(algo);
902       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
903       {
904         if (_father->IsUsedHypothesis( anHyp, this )) // new Hyp
905           modifiedHyp = true;
906       }
907       else
908         SetAlgoState(MISSING_HYP);
909       break;
910     }
911     case ADD_FATHER_ALGO: {
912       algo = gen->GetAlgo((*_father), _subShape);
913       if ( algo == anHyp ) { // a new algo on father
914         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
915           // check if algo changes
916           SMESH_HypoFilter f;
917           f.Init(   SMESH_HypoFilter::IsAlgo() );
918           f.And(    SMESH_HypoFilter::IsApplicableTo( _subShape ));
919           f.AndNot( SMESH_HypoFilter::Is( algo ));
920           const SMESH_Hypothesis* prevAlgo = _father->GetHypothesis( _subShape, f, true );
921           if (prevAlgo &&
922               string(algo->GetName()) != string(prevAlgo->GetName()) )
923             modifiedHyp = true;
924         }
925         else
926           SetAlgoState(MISSING_HYP);
927       }
928       break;
929     }
930     case REMOVE_FATHER_HYP: {
931       algo = gen->GetAlgo((*_father), _subShape);
932       ASSERT(algo);
933       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
934         // is there the same local hyp or maybe a new father algo applied?
935         if ( !GetSimilarAttached( _subShape, anHyp ) )
936           modifiedHyp = true;
937       }
938       else
939         SetAlgoState(MISSING_HYP);
940       break;
941     }
942     case REMOVE_FATHER_ALGO: {
943       algo = gen->GetAlgo((*_father), _subShape);
944       if (algo == NULL)  // no more applying algo on father
945       {
946         SetAlgoState(NO_ALGO);
947       }
948       else
949       {
950         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
951           // check if algo changes
952           if ( string(algo->GetName()) != string( anHyp->GetName()) )
953             modifiedHyp = true;
954         }
955         else
956           SetAlgoState(MISSING_HYP);
957       }
958       break;
959     }
960     default:
961       ASSERT(0);
962       break;
963     }
964     break;
965
966     // ----------------------------------------------------------------------
967
968   default:
969     ASSERT(0);
970     break;
971   }
972
973   if ( _algoState != oldAlgoState )
974   {
975     if (_algoState == HYP_OK )
976       algo->SetEventListener( this );
977     if ( oldAlgoState == HYP_OK )
978       DeleteOwnListeners();
979   }
980   NotifyListenersOnEvent( event, ALGO_EVENT, anHyp );
981
982   if (_algoState != oldAlgoState || modifiedHyp)
983     ComputeStateEngine(MODIF_ALGO_STATE);
984
985   return ret;
986 }
987
988
989 //=======================================================================
990 //function : IsConform
991 //purpose  : check if a conform mesh will be produced by the Algo
992 //=======================================================================
993
994 bool SMESH_subMesh::IsConform(const SMESH_Algo* theAlgo)
995 {
996 //  MESSAGE( "SMESH_subMesh::IsConform" );
997
998   if ( !theAlgo ) return false;
999
1000   // check only algo that doesn't NeedDescretBoundary(): because mesh made
1001   // on a sub-shape will be ignored by theAlgo
1002   if ( theAlgo->NeedDescretBoundary() )
1003     return true;
1004
1005   SMESH_Gen* gen =_father->GetGen();
1006
1007   // only local algo is to be checked
1008   if ( gen->IsGlobalHypothesis( theAlgo, *_father ))
1009     return true;
1010
1011   // check algo attached to adjacent shapes
1012
1013   // loop on one level down sub-meshes
1014   TopoDS_Iterator itsub( _subShape );
1015   for (; itsub.More(); itsub.Next())
1016   {
1017     // loop on adjacent subShapes
1018     TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( itsub.Value() ));
1019     for (; it.More(); it.Next())
1020     {
1021       const TopoDS_Shape& adjacent = it.Value();
1022       if ( _subShape.IsSame( adjacent )) continue;
1023       if ( adjacent.ShapeType() != _subShape.ShapeType())
1024         break;
1025
1026       // check algo attached to smAdjacent
1027       SMESH_Algo * algo = gen->GetAlgo((*_father), adjacent);
1028       if (algo &&
1029           //algo != theAlgo &&
1030           !algo->NeedDescretBoundary() /*&&
1031           !gen->IsGlobalHypothesis( algo, *_father )*/)
1032         return false; // NOT CONFORM MESH WILL BE PRODUCED
1033     }
1034   }
1035
1036   return true;
1037 }
1038
1039 //=============================================================================
1040 /*!
1041  *
1042  */
1043 //=============================================================================
1044
1045 void SMESH_subMesh::SetAlgoState(int state)
1046 {
1047   _algoState = state;
1048 }
1049
1050 //=============================================================================
1051 /*!
1052  *
1053  */
1054 //=============================================================================
1055 SMESH_Hypothesis::Hypothesis_Status
1056   SMESH_subMesh::SubMeshesAlgoStateEngine(int event,
1057                                           SMESH_Hypothesis * anHyp)
1058 {
1059   //MESSAGE("SMESH_subMesh::SubMeshesAlgoStateEngine");
1060   SMESH_Hypothesis::Hypothesis_Status ret = SMESH_Hypothesis::HYP_OK;
1061   //EAP: a wire (dim==1) should notify edges (dim==1)
1062   //EAP: int dim = SMESH_Gen::GetShapeDim(_subShape);
1063   if (_subShape.ShapeType() < TopAbs_EDGE ) // wire,face etc
1064   {
1065     const map < int, SMESH_subMesh * >&subMeshes = DependsOn();
1066
1067     map < int, SMESH_subMesh * >::const_iterator itsub;
1068     for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++)
1069     {
1070       SMESH_subMesh *sm = (*itsub).second;
1071       SMESH_Hypothesis::Hypothesis_Status ret2 =
1072         sm->AlgoStateEngine(event, anHyp);
1073       if ( ret2 > ret )
1074         ret = ret2;
1075     }
1076   }
1077   return ret;
1078 }
1079
1080 //=============================================================================
1081 /*!
1082  *
1083  */
1084 //=============================================================================
1085
1086 void SMESH_subMesh::CleanDependsOn()
1087 {
1088   //MESSAGE("SMESH_subMesh::CleanDependsOn");
1089
1090   const map < int, SMESH_subMesh * >&dependson = DependsOn();
1091   map < int, SMESH_subMesh * >::const_iterator its;
1092   for (its = dependson.begin(); its != dependson.end(); its++)
1093   {
1094     SMESH_subMesh *sm = (*its).second;
1095     sm->ComputeStateEngine(CLEAN);
1096   }
1097 }
1098
1099 //=============================================================================
1100 /*!
1101  *
1102  */
1103 //=============================================================================
1104
1105 void SMESH_subMesh::DumpAlgoState(bool isMain)
1106 {
1107         int dim = SMESH_Gen::GetShapeDim(_subShape);
1108 //   if (dim < 1) return;
1109         if (isMain)
1110         {
1111                 const map < int, SMESH_subMesh * >&subMeshes = DependsOn();
1112
1113                 map < int, SMESH_subMesh * >::const_iterator itsub;
1114                 for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++)
1115                 {
1116                         SMESH_subMesh *sm = (*itsub).second;
1117                         sm->DumpAlgoState(false);
1118                 }
1119         }
1120         int type = _subShape.ShapeType();
1121         MESSAGE("dim = " << dim << " type of shape " << type);
1122         switch (_algoState)
1123         {
1124         case NO_ALGO:
1125                 MESSAGE(" AlgoState = NO_ALGO");
1126                 break;
1127         case MISSING_HYP:
1128                 MESSAGE(" AlgoState = MISSING_HYP");
1129                 break;
1130         case HYP_OK:
1131                 MESSAGE(" AlgoState = HYP_OK");
1132                 break;
1133         }
1134         switch (_computeState)
1135         {
1136         case NOT_READY:
1137                 MESSAGE(" ComputeState = NOT_READY");
1138                 break;
1139         case READY_TO_COMPUTE:
1140                 MESSAGE(" ComputeState = READY_TO_COMPUTE");
1141                 break;
1142         case COMPUTE_OK:
1143                 MESSAGE(" ComputeState = COMPUTE_OK");
1144                 break;
1145         case FAILED_TO_COMPUTE:
1146                 MESSAGE(" ComputeState = FAILED_TO_COMPUTE");
1147                 break;
1148         }
1149 }
1150
1151 //================================================================================
1152 /*!
1153  * \brief Remove nodes and elements bound to submesh
1154   * \param subMesh - submesh containing nodes and elements
1155  */
1156 //================================================================================
1157
1158 static void cleanSubMesh( SMESH_subMesh * subMesh )
1159 {
1160   if (subMesh) {
1161     if (SMESHDS_SubMesh * subMeshDS = subMesh->GetSubMeshDS()) {
1162       SMESHDS_Mesh * meshDS = subMesh->GetFather()->GetMeshDS();
1163       SMDS_ElemIteratorPtr ite = subMeshDS->GetElements();
1164       while (ite->more()) {
1165         const SMDS_MeshElement * elt = ite->next();
1166         //MESSAGE( " RM elt: "<<elt->GetID()<<" ( "<<elt->NbNodes()<<" )" );
1167         //meshDS->RemoveElement(elt);
1168         meshDS->RemoveFreeElement(elt, subMeshDS);
1169       }
1170
1171       SMDS_NodeIteratorPtr itn = subMeshDS->GetNodes();
1172       while (itn->more()) {
1173         const SMDS_MeshNode * node = itn->next();
1174         //MESSAGE( " RM node: "<<node->GetID());
1175         //meshDS->RemoveNode(node);
1176         meshDS->RemoveFreeNode(node, subMeshDS);
1177       }
1178     }
1179   }
1180 }
1181
1182 //=============================================================================
1183 /*!
1184  *
1185  */
1186 //=============================================================================
1187
1188 bool SMESH_subMesh::ComputeStateEngine(int event)
1189 {
1190   //MESSAGE("SMESH_subMesh::ComputeStateEngine");
1191   //SCRUTE(_computeState);
1192   //SCRUTE(event);
1193
1194   int dim = SMESH_Gen::GetShapeDim(_subShape);
1195
1196   if (dim < 1)
1197   {
1198     if ( IsMeshComputed() )
1199       _computeState = COMPUTE_OK;
1200     else
1201       _computeState = READY_TO_COMPUTE;
1202     return true;
1203   }
1204   SMESH_Gen *gen = _father->GetGen();
1205   SMESH_Algo *algo = 0;
1206   bool ret = true;
1207   SMESH_Hypothesis::Hypothesis_Status hyp_status;
1208   algo_state oldAlgoState = (algo_state) GetAlgoState();
1209
1210   switch (_computeState)
1211   {
1212
1213     // ----------------------------------------------------------------------
1214
1215   case NOT_READY:
1216     switch (event)
1217     {
1218     case MODIF_HYP:
1219     case MODIF_ALGO_STATE:
1220       algo = gen->GetAlgo((*_father), _subShape);
1221       if (algo && !algo->NeedDescretBoundary())
1222         CleanDependsOn(); // clean sub-meshes with event CLEAN
1223       if (algo)
1224       {
1225         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1226         if (ret)
1227           _computeState = READY_TO_COMPUTE;
1228       }
1229       if ( _computeState == READY_TO_COMPUTE )
1230           SetAlgoState(HYP_OK);
1231       else
1232           SetAlgoState(MISSING_HYP);
1233       break;
1234     case COMPUTE:               // nothing to do
1235       break;
1236     case CLEAN:
1237       CleanDependants();
1238       RemoveSubMeshElementsAndNodes();
1239       break;
1240     case SUBMESH_COMPUTED:      // nothing to do
1241       break;
1242     case SUBMESH_RESTORED:
1243       ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
1244       break;
1245     case MESH_ENTITY_REMOVED:
1246       break;
1247     case CHECK_COMPUTE_STATE:
1248       if ( IsMeshComputed() )
1249         _computeState = COMPUTE_OK;
1250       break;
1251     default:
1252       ASSERT(0);
1253       break;
1254     }
1255     break;
1256
1257     // ----------------------------------------------------------------------
1258
1259   case READY_TO_COMPUTE:
1260     switch (event)
1261     {
1262     case MODIF_HYP:
1263     case MODIF_ALGO_STATE:
1264       algo = gen->GetAlgo((*_father), _subShape);
1265       if (algo && !algo->NeedDescretBoundary())
1266         CleanDependsOn(); // clean sub-meshes with event CLEAN
1267       _computeState = NOT_READY;
1268       if (algo)
1269       {
1270         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1271         if (ret) {
1272           SetAlgoState(HYP_OK); // it might be KO if BAD_PARAM_VALUE
1273           _computeState = READY_TO_COMPUTE;
1274         }
1275         else
1276           SetAlgoState(MISSING_HYP);
1277       }
1278       break;
1279     case COMPUTE:
1280       {
1281         algo = gen->GetAlgo((*_father), _subShape);
1282         ASSERT(algo);
1283         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1284         if (!ret)
1285         {
1286           MESSAGE("***** verify compute state *****");
1287           _computeState = NOT_READY;
1288           SetAlgoState(MISSING_HYP);
1289           break;
1290         }
1291         // check submeshes needed
1292         if (algo->NeedDescretBoundary())
1293           ret = SubMeshesComputed();
1294         if (!ret)
1295         {
1296           MESSAGE("Some SubMeshes not computed");
1297           _computeState = FAILED_TO_COMPUTE;
1298           break;
1299         }
1300         // compute
1301         CleanDependants();
1302         RemoveSubMeshElementsAndNodes();
1303         {
1304           try {
1305 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1306             OCC_CATCH_SIGNALS;
1307 #endif
1308             if (!algo->NeedDescretBoundary() && !algo->OnlyUnaryInput())
1309               ret = ApplyToCollection( algo, GetCollection( gen, algo ) );
1310             else
1311               ret = algo->Compute((*_father), _subShape);
1312           }
1313           catch (Standard_Failure) {
1314             MESSAGE( "Exception in algo->Compute() ");
1315             ret = false;
1316           }
1317         }
1318         if (!ret)
1319         {
1320           MESSAGE("problem in algo execution: failed to compute");
1321           // release ALGO from responsibilty of partially built mesh
1322           RemoveSubMeshElementsAndNodes();
1323           _computeState = FAILED_TO_COMPUTE;
1324           if (!algo->NeedDescretBoundary())
1325             UpdateSubMeshState( FAILED_TO_COMPUTE );
1326
1327 #ifdef _DEBUG_
1328           // Show vertices location of a failed shape
1329           cout << algo->GetName() << " failed on shape with the following vertices:" << endl;
1330           TopTools_IndexedMapOfShape vMap;
1331           TopExp::MapShapes( _subShape, TopAbs_VERTEX, vMap );
1332           for ( int iv = 1; iv <= vMap.Extent(); ++iv ) {
1333             gp_Pnt P( BRep_Tool::Pnt( TopoDS::Vertex( vMap( iv ) )));
1334             cout << P.X() << " " << P.Y() << " " << P.Z() << " " << endl;
1335           }
1336 #endif
1337           break;
1338         }
1339         else
1340         {
1341           _computeState = COMPUTE_OK;
1342           UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
1343           if (!algo->NeedDescretBoundary())
1344             UpdateSubMeshState( COMPUTE_OK );
1345         }
1346       }
1347       break;
1348     case CLEAN:
1349       CleanDependants();
1350       RemoveSubMeshElementsAndNodes();
1351       _computeState = NOT_READY;
1352       algo = gen->GetAlgo((*_father), _subShape);
1353       if (algo)
1354       {
1355         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1356         if (ret)
1357           _computeState = READY_TO_COMPUTE;
1358         else
1359           SetAlgoState(MISSING_HYP);
1360       }
1361       break;
1362     case SUBMESH_COMPUTED:      // nothing to do
1363       break;
1364     case SUBMESH_RESTORED:
1365       // check if a mesh is already computed that may
1366       // happen after retrieval from a file
1367       ComputeStateEngine( CHECK_COMPUTE_STATE );
1368       ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
1369       break;
1370     case MESH_ENTITY_REMOVED:
1371       break;
1372     case CHECK_COMPUTE_STATE:
1373       if ( IsMeshComputed() )
1374         _computeState = COMPUTE_OK;
1375       break;
1376     default:
1377       ASSERT(0);
1378       break;
1379     }
1380     break;
1381
1382     // ----------------------------------------------------------------------
1383
1384   case COMPUTE_OK:
1385     switch (event)
1386     {
1387     case MODIF_HYP:
1388     case MODIF_ALGO_STATE:
1389       ComputeStateEngine( CLEAN );
1390       algo = gen->GetAlgo((*_father), _subShape);
1391       if (algo && !algo->NeedDescretBoundary())
1392         CleanDependsOn(); // clean sub-meshes with event CLEAN
1393       break;
1394     case COMPUTE:               // nothing to do
1395       break;
1396     case CLEAN:
1397       CleanDependants();  // clean sub-meshes, dependant on this one, with event CLEAN
1398       RemoveSubMeshElementsAndNodes();
1399       _computeState = NOT_READY;
1400       algo = gen->GetAlgo((*_father), _subShape);
1401       if (algo)
1402       {
1403         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1404         if (ret)
1405           _computeState = READY_TO_COMPUTE;
1406         else
1407           SetAlgoState(MISSING_HYP);
1408       }
1409       break;
1410     case SUBMESH_COMPUTED:      // nothing to do
1411       break;
1412     case SUBMESH_RESTORED:
1413       ComputeStateEngine( CHECK_COMPUTE_STATE );
1414       ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
1415       break;
1416     case MESH_ENTITY_REMOVED:
1417       UpdateDependantsState( CHECK_COMPUTE_STATE );
1418       ComputeStateEngine( CHECK_COMPUTE_STATE );
1419       ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
1420       break;
1421     case CHECK_COMPUTE_STATE:
1422       if ( !IsMeshComputed() )
1423         if (_algoState == HYP_OK)
1424           _computeState = READY_TO_COMPUTE;
1425         else
1426           _computeState = NOT_READY;
1427       break;
1428     default:
1429       ASSERT(0);
1430       break;
1431     }
1432     break;
1433
1434     // ----------------------------------------------------------------------
1435
1436   case FAILED_TO_COMPUTE:
1437     switch (event)
1438     {
1439     case MODIF_HYP:
1440       if (_algoState == HYP_OK)
1441         _computeState = READY_TO_COMPUTE;
1442       else
1443         _computeState = NOT_READY;
1444       break;
1445     case MODIF_ALGO_STATE:
1446       if (_algoState == HYP_OK)
1447         _computeState = READY_TO_COMPUTE;
1448       else
1449         _computeState = NOT_READY;
1450       break;
1451     case COMPUTE:      // nothing to do
1452       break;
1453     case CLEAN:
1454       CleanDependants(); // submeshes dependent on me should be cleaned as well
1455       RemoveSubMeshElementsAndNodes();
1456       if (_algoState == HYP_OK)
1457         _computeState = READY_TO_COMPUTE;
1458       else
1459         _computeState = NOT_READY;
1460       break;
1461     case SUBMESH_COMPUTED:      // allow retry compute
1462       if (_algoState == HYP_OK)
1463         _computeState = READY_TO_COMPUTE;
1464       else
1465         _computeState = NOT_READY;
1466       break;
1467     case SUBMESH_RESTORED:
1468       ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
1469       break;
1470     case MESH_ENTITY_REMOVED:
1471       break;
1472     case CHECK_COMPUTE_STATE:
1473       if ( IsMeshComputed() )
1474         _computeState = COMPUTE_OK;
1475       else
1476         if (_algoState == HYP_OK)
1477           _computeState = READY_TO_COMPUTE;
1478         else
1479           _computeState = NOT_READY;
1480       break;
1481     default:
1482       ASSERT(0);
1483       break;
1484     }
1485     break;
1486
1487     // ----------------------------------------------------------------------
1488   default:
1489     ASSERT(0);
1490     break;
1491   }
1492
1493   if ( _algoState != oldAlgoState || event == MODIF_HYP )
1494   {
1495     if ( oldAlgoState == HYP_OK )
1496       DeleteOwnListeners();
1497     if (_algoState == HYP_OK && algo )
1498       algo->SetEventListener( this );
1499   }
1500   NotifyListenersOnEvent( event, COMPUTE_EVENT );
1501
1502   //SCRUTE(_computeState);
1503   return ret;
1504 }
1505
1506 //=======================================================================
1507 //function : ApplyToCollection
1508 //purpose  : Apply theAlgo to all subshapes in theCollection
1509 //=======================================================================
1510
1511 bool SMESH_subMesh::ApplyToCollection (SMESH_Algo*         theAlgo,
1512                                        const TopoDS_Shape& theCollection)
1513 {
1514   MESSAGE("SMESH_subMesh::ApplyToCollection");
1515   ASSERT ( !theAlgo->NeedDescretBoundary() );
1516
1517   bool ret = false;
1518
1519
1520   ret = theAlgo->Compute( *_father, theCollection );
1521
1522   // set _computeState of subshapes
1523   TopExp_Explorer anExplorer( theCollection, _subShape.ShapeType() );
1524   for ( ; anExplorer.More(); anExplorer.Next() )
1525   {
1526     const TopoDS_Shape& aSubShape = anExplorer.Current();
1527     SMESH_subMesh* subMesh = _father->GetSubMeshContaining( aSubShape );
1528     if ( subMesh )
1529     {
1530       if (ret)
1531       {
1532         subMesh->_computeState = COMPUTE_OK;
1533         subMesh->UpdateDependantsState( SUBMESH_COMPUTED );
1534         subMesh->UpdateSubMeshState( COMPUTE_OK );
1535       }
1536       else
1537       {
1538         subMesh->_computeState = FAILED_TO_COMPUTE;
1539       }
1540     }
1541   }
1542   return ret;
1543 }
1544
1545
1546 //=======================================================================
1547 //function : UpdateSubMeshState
1548 //purpose  :
1549 //=======================================================================
1550
1551 void SMESH_subMesh::UpdateSubMeshState(const compute_state theState)
1552 {
1553   const map<int, SMESH_subMesh*>& smMap = DependsOn();
1554   map<int, SMESH_subMesh*>::const_iterator itsub;
1555   for (itsub = smMap.begin(); itsub != smMap.end(); itsub++)
1556   {
1557     SMESH_subMesh* sm = (*itsub).second;
1558     sm->_computeState = theState;
1559   }
1560 }
1561
1562 //=======================================================================
1563 //function : ComputeSubMeshStateEngine
1564 //purpose  :
1565 //=======================================================================
1566
1567 void SMESH_subMesh::ComputeSubMeshStateEngine(int event)
1568 {
1569   const map<int, SMESH_subMesh*>& smMap = DependsOn();
1570   map<int, SMESH_subMesh*>::const_iterator itsub;
1571   for (itsub = smMap.begin(); itsub != smMap.end(); itsub++)
1572   {
1573     SMESH_subMesh* sm = (*itsub).second;
1574     sm->ComputeStateEngine(event);
1575   }
1576 }
1577
1578 //=======================================================================
1579 //function : UpdateDependantsState
1580 //purpose  :
1581 //=======================================================================
1582
1583 void SMESH_subMesh::UpdateDependantsState(const compute_event theEvent)
1584 {
1585   //MESSAGE("SMESH_subMesh::UpdateDependantsState");
1586   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1587   for (; it.More(); it.Next())
1588   {
1589     const TopoDS_Shape& ancestor = it.Value();
1590     SMESH_subMesh *aSubMesh =
1591       _father->GetSubMeshContaining(ancestor);
1592     if (aSubMesh)
1593       aSubMesh->ComputeStateEngine( theEvent );
1594   }
1595 }
1596
1597 //=============================================================================
1598 /*!
1599  *
1600  */
1601 //=============================================================================
1602
1603 void SMESH_subMesh::CleanDependants()
1604 {
1605   int dimToClean = SMESH_Gen::GetShapeDim( _subShape ) + 1;
1606
1607   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1608   for (; it.More(); it.Next())
1609   {
1610     const TopoDS_Shape& ancestor = it.Value();
1611     if ( SMESH_Gen::GetShapeDim( ancestor ) == dimToClean ) {
1612       // PAL8021. do not go upper than SOLID, else ComputeStateEngine(CLEAN)
1613       // will erase mesh on other shapes in a compound
1614       if ( ancestor.ShapeType() >= TopAbs_SOLID ) {
1615         SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor);
1616         if (aSubMesh)
1617           aSubMesh->ComputeStateEngine(CLEAN);
1618       }
1619     }
1620   }
1621 }
1622
1623 //=============================================================================
1624 /*!
1625  *
1626  */
1627 //=============================================================================
1628
1629 void SMESH_subMesh::RemoveSubMeshElementsAndNodes()
1630 {
1631   //SCRUTE(_subShape.ShapeType());
1632
1633   cleanSubMesh( this );
1634
1635   // algo may bind a submesh not to _subShape, eg 3D algo
1636   // sets nodes on SHELL while _subShape may be SOLID
1637
1638   int dim = SMESH_Gen::GetShapeDim( _subShape );
1639   int type = _subShape.ShapeType() + 1;
1640   for ( ; type <= TopAbs_EDGE; type++) {
1641     if ( dim == SMESH_Gen::GetShapeDim( (TopAbs_ShapeEnum) type ))
1642     {
1643       TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type );
1644       for ( ; exp.More(); exp.Next() )
1645         cleanSubMesh( _father->GetSubMeshContaining( exp.Current() ));
1646     }
1647     else
1648       break;
1649   }
1650 }
1651
1652 //=======================================================================
1653 //function : IsMeshComputed
1654 //purpose  : check if _subMeshDS contains mesh elements
1655 //=======================================================================
1656
1657 bool SMESH_subMesh::IsMeshComputed() const
1658 {
1659   // algo may bind a submesh not to _subShape, eg 3D algo
1660   // sets nodes on SHELL while _subShape may be SOLID
1661
1662   int dim = SMESH_Gen::GetShapeDim( _subShape );
1663   int type = _subShape.ShapeType();
1664   for ( ; type <= TopAbs_VERTEX; type++) {
1665     if ( dim == SMESH_Gen::GetShapeDim( (TopAbs_ShapeEnum) type ))
1666     {
1667       TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type );
1668       for ( ; exp.More(); exp.Next() )
1669       {
1670         SMESHDS_SubMesh * smDS = _meshDS->MeshElements( exp.Current() );
1671         if ( smDS && ( smDS->NbElements() || smDS->NbNodes()))
1672           return true;
1673       }
1674     }
1675     else
1676       break;
1677   }
1678
1679   return false;
1680 }
1681
1682
1683 //=======================================================================
1684 //function : GetCollection
1685 //purpose  : return a shape containing all sub-shapes of the MainShape that can be
1686 //           meshed at once along with _subShape
1687 //=======================================================================
1688
1689 TopoDS_Shape SMESH_subMesh::GetCollection(SMESH_Gen * theGen, SMESH_Algo* theAlgo)
1690 {
1691   MESSAGE("SMESH_subMesh::GetCollection");
1692   ASSERT (!theAlgo->NeedDescretBoundary());
1693
1694   TopoDS_Shape mainShape = _father->GetMeshDS()->ShapeToMesh();
1695
1696   if ( mainShape.IsSame( _subShape ))
1697     return _subShape;
1698
1699   const bool ignoreAuxiliaryHyps = false;
1700   list<const SMESHDS_Hypothesis*> aUsedHyp =
1701     theAlgo->GetUsedHypothesis( *_father, _subShape, ignoreAuxiliaryHyps ); // copy
1702
1703   // put in a compound all shapes with the same hypothesis assigned
1704   // and a good ComputState
1705
1706   TopoDS_Compound aCompound;
1707   BRep_Builder aBuilder;
1708   aBuilder.MakeCompound( aCompound );
1709
1710   TopExp_Explorer anExplorer( mainShape, _subShape.ShapeType() );
1711   for ( ; anExplorer.More(); anExplorer.Next() )
1712   {
1713     const TopoDS_Shape& S = anExplorer.Current();
1714     SMESH_subMesh* subMesh = _father->GetSubMesh( S );
1715     SMESH_Algo* anAlgo = theGen->GetAlgo( *_father, S );
1716
1717     if (subMesh->GetComputeState() == READY_TO_COMPUTE &&
1718         anAlgo == theAlgo &&
1719         anAlgo->GetUsedHypothesis( *_father, S, ignoreAuxiliaryHyps ) == aUsedHyp)
1720     {
1721       aBuilder.Add( aCompound, S );
1722     }
1723   }
1724
1725   return aCompound;
1726 }
1727
1728 //=======================================================================
1729 //function : GetSimilarAttached
1730 //purpose  : return a hypothesis attached to theShape.
1731 //           If theHyp is provided, similar but not same hypotheses
1732 //           is returned; else only applicable ones having theHypType
1733 //           is returned
1734 //=======================================================================
1735
1736 const SMESH_Hypothesis* SMESH_subMesh::GetSimilarAttached(const TopoDS_Shape&      theShape,
1737                                                           const SMESH_Hypothesis * theHyp,
1738                                                           const int                theHypType)
1739 {
1740   SMESH_HypoFilter hypoKind;
1741   hypoKind.Init( hypoKind.HasType( theHyp ? theHyp->GetType() : theHypType ));
1742   if ( theHyp ) {
1743     hypoKind.And   ( hypoKind.HasDim( theHyp->GetDim() ));
1744     hypoKind.AndNot( hypoKind.Is( theHyp ));
1745     if ( theHyp->IsAuxiliary() )
1746       hypoKind.And( hypoKind.HasName( theHyp->GetName() ));
1747     else
1748       hypoKind.AndNot( hypoKind.IsAuxiliary());
1749   }
1750   else {
1751     hypoKind.And( hypoKind.IsApplicableTo( theShape ));
1752   }
1753
1754   return _father->GetHypothesis( theShape, hypoKind, false );
1755 }
1756
1757 //=======================================================================
1758 //function : CheckConcurentHypothesis
1759 //purpose  : check if there are several applicable hypothesis attached to
1760 //           ansestors
1761 //=======================================================================
1762
1763 SMESH_Hypothesis::Hypothesis_Status
1764   SMESH_subMesh::CheckConcurentHypothesis (const int theHypType)
1765 {
1766   MESSAGE ("SMESH_subMesh::CheckConcurentHypothesis");
1767
1768   // is there local hypothesis on me?
1769   if ( GetSimilarAttached( _subShape, 0, theHypType ) )
1770     return SMESH_Hypothesis::HYP_OK;
1771
1772
1773   TopoDS_Shape aPrevWithHyp;
1774   const SMESH_Hypothesis* aPrevHyp = 0;
1775   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1776   for (; it.More(); it.Next())
1777   {
1778     const TopoDS_Shape& ancestor = it.Value();
1779     const SMESH_Hypothesis* hyp = GetSimilarAttached( ancestor, 0, theHypType );
1780     if ( hyp )
1781     {
1782       if ( aPrevWithHyp.IsNull() || aPrevWithHyp.IsSame( ancestor ))
1783       {
1784         aPrevWithHyp = ancestor;
1785         aPrevHyp     = hyp;
1786       }
1787       else if ( aPrevWithHyp.ShapeType() == ancestor.ShapeType() && aPrevHyp != hyp )
1788         return SMESH_Hypothesis::HYP_CONCURENT;
1789       else
1790         return SMESH_Hypothesis::HYP_OK;
1791     }
1792   }
1793   return SMESH_Hypothesis::HYP_OK;
1794 }
1795
1796 //================================================================================
1797 /*!
1798  * \brief Sets an event listener and its data to a submesh
1799  * \param listener - the listener to store
1800  * \param data - the listener data to store
1801  * \param where - the submesh to store the listener and it's data
1802  * \param deleteListener - if true then the listener will be deleted as
1803  *        it is removed from where submesh
1804  * 
1805  * It remembers the submesh where it puts the listener in order to delete
1806  * them when HYP_OK algo_state is lost
1807  * After being set, event listener is notified on each event of where submesh.
1808  */
1809 //================================================================================
1810
1811 void SMESH_subMesh::SetEventListener(EventListener*     listener,
1812                                      EventListenerData* data,
1813                                      SMESH_subMesh*     where)
1814 {
1815   if ( listener && where ) {
1816     where->SetEventListener( listener, data );
1817     myOwnListeners.push_back( make_pair( where, listener ));
1818   }
1819 }
1820
1821 //================================================================================
1822 /*!
1823  * \brief Sets an event listener and its data to a submesh
1824  * \param listener - the listener to store
1825  * \param data - the listener data to store
1826  * 
1827  * After being set, event listener is notified on each event of a submesh.
1828  */
1829 //================================================================================
1830
1831 void SMESH_subMesh::SetEventListener(EventListener* listener, EventListenerData* data)
1832 {
1833   myEventListeners.insert( make_pair( listener, data ));
1834 }
1835
1836 //================================================================================
1837 /*!
1838  * \brief Return an event listener data
1839  * \param listener - the listener whose data is
1840  * \retval EventListenerData* - found data, maybe NULL
1841  */
1842 //================================================================================
1843
1844 EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener) const
1845 {
1846   map< EventListener*, EventListenerData* >::const_iterator l_d =
1847     myEventListeners.find( listener );
1848   if ( l_d != myEventListeners.end() )
1849     return l_d->second;
1850   return 0;
1851 }
1852
1853 //================================================================================
1854 /*!
1855  * \brief Notify stored event listeners on the occured event
1856  * \param event - algo_event or compute_event itself
1857  * \param eventType - algo_event or compute_event
1858  * \param subMesh - the submesh where the event occures
1859  * \param data - listener data stored in the subMesh
1860  * \param hyp - hypothesis, if eventType is algo_event
1861  */
1862 //================================================================================
1863
1864 void SMESH_subMesh::NotifyListenersOnEvent( const int         event,
1865                                             const event_type  eventType,
1866                                             SMESH_Hypothesis* hyp)
1867 {
1868   map< EventListener*, EventListenerData* >::iterator l_d = myEventListeners.begin();
1869   for ( ; l_d != myEventListeners.end(); ++l_d )
1870     l_d->first->ProcessEvent( event, eventType, this, l_d->second, hyp );
1871 }
1872
1873 //================================================================================
1874 /*!
1875  * \brief Unregister the listener and delete listener's data
1876  * \param listener - the event listener
1877  */
1878 //================================================================================
1879
1880 void SMESH_subMesh::DeleteEventListener(EventListener* listener)
1881 {
1882   map< EventListener*, EventListenerData* >::iterator l_d =
1883     myEventListeners.find( listener );
1884   if ( l_d != myEventListeners.end() ) {
1885     if ( l_d->first->IsDeletable() ) delete l_d->first;
1886     if ( l_d->second->IsDeletable() ) delete l_d->second;
1887     myEventListeners.erase( l_d );
1888   }
1889 }
1890
1891 //================================================================================
1892 /*!
1893  * \brief Delete event listeners depending on algo of this submesh
1894  */
1895 //================================================================================
1896
1897 void SMESH_subMesh::DeleteOwnListeners()
1898 {
1899   list< pair< SMESH_subMesh*, EventListener* > >::iterator sm_l;
1900   for ( sm_l = myOwnListeners.begin(); sm_l != myOwnListeners.end(); ++sm_l)
1901     sm_l->first->DeleteEventListener( sm_l->second );
1902   myOwnListeners.clear();
1903 }
1904
1905 //================================================================================
1906 /*!
1907  * \brief Do something on a certain event
1908  * \param event - algo_event or compute_event itself
1909  * \param eventType - algo_event or compute_event
1910  * \param subMesh - the submesh where the event occures
1911  * \param data - listener data stored in the subMesh
1912  * \param hyp - hypothesis, if eventType is algo_event
1913  * 
1914  * The base implementation translates CLEAN event to the subMesh
1915  * stored in listener data. Also it sends SUBMESH_COMPUTED event in case of
1916  * successful COMPUTE event.
1917  */
1918 //================================================================================
1919
1920 void SMESH_subMeshEventListener::ProcessEvent(const int          event,
1921                                               const int          eventType,
1922                                               SMESH_subMesh*     subMesh,
1923                                               EventListenerData* data,
1924                                               SMESH_Hypothesis*  /*hyp*/)
1925 {
1926   if ( data && !data->mySubMeshes.empty() &&
1927        eventType == SMESH_subMesh::COMPUTE_EVENT)
1928   {
1929     ASSERT( data->mySubMeshes.front() != subMesh );
1930     switch ( event ) {
1931     case SMESH_subMesh::CLEAN:
1932       data->mySubMeshes.front()->ComputeStateEngine( event );
1933       break;
1934     case SMESH_subMesh::COMPUTE:
1935       if ( subMesh->GetComputeState() == SMESH_subMesh::COMPUTE_OK )
1936         data->mySubMeshes.front()->ComputeStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
1937       break;
1938     default:;
1939     }
1940   }
1941 }