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