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