Salome HOME
0020105: EDF 862 SMESH : Creation of the skin elements (2D) of a 3D Mesh
[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       algo = gen->GetAlgo((*_father), _subShape);
951       if (algo == NULL)  // no more applying algo on father
952       {
953         SetAlgoState(NO_ALGO);
954       }
955       else
956       {
957         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
958           // check if algo changes
959           if ( string(algo->GetName()) != string( anHyp->GetName()) )
960             modifiedHyp = true;
961         }
962         else
963           SetAlgoState(MISSING_HYP);
964       }
965       break;
966     }
967     default:
968       ASSERT(0);
969       break;
970     }
971     break;
972
973     // ----------------------------------------------------------------------
974
975   default:
976     ASSERT(0);
977     break;
978   }
979
980   // detect algorithm hiding
981   //
982   if ( ret == SMESH_Hypothesis::HYP_OK &&
983        ( event == ADD_ALGO || event == ADD_FATHER_ALGO ) &&
984        algo->GetName() == anHyp->GetName() )
985   {
986     // is algo hidden?
987     SMESH_Gen* gen = _father->GetGen();
988     TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
989     for ( ; ( ret == SMESH_Hypothesis::HYP_OK && it.More()); it.Next() ) {
990       if ( SMESH_Algo* upperAlgo = gen->GetAlgo( *_father, it.Value() ))
991         if ( !upperAlgo->NeedDescretBoundary() && !upperAlgo->SupportSubmeshes())
992           ret = SMESH_Hypothesis::HYP_HIDDEN_ALGO;
993     }
994     // is algo hiding?
995     if ( ret == SMESH_Hypothesis::HYP_OK &&
996          !algo->NeedDescretBoundary()    &&
997          !algo->SupportSubmeshes()) {
998       map<int, SMESH_subMesh*>::reverse_iterator i_sm = _mapDepend.rbegin();
999       for ( ; ( ret == SMESH_Hypothesis::HYP_OK && i_sm != _mapDepend.rend()) ; ++i_sm )
1000         if ( gen->GetAlgo( *_father, i_sm->second->_subShape ))
1001           ret = SMESH_Hypothesis::HYP_HIDING_ALGO;
1002     }
1003   }
1004
1005   bool stateChange = ( _algoState != oldAlgoState );
1006
1007   if ( stateChange && _algoState == HYP_OK ) // hyp becomes OK
1008     algo->SetEventListener( this );
1009
1010   NotifyListenersOnEvent( event, ALGO_EVENT, anHyp );
1011
1012   if ( stateChange && oldAlgoState == HYP_OK ) { // hyp becomes KO
1013     DeleteOwnListeners();
1014     SetIsAlwaysComputed( false );
1015     if (_subShape.ShapeType() == TopAbs_VERTEX ) {
1016       // restore default states
1017       _algoState = HYP_OK;
1018       _computeState = READY_TO_COMPUTE;
1019     }
1020   }
1021
1022   if ( needFullClean ) {
1023     // added or removed algo is all-dimensional
1024     ComputeStateEngine( CLEAN );
1025     CleanDependsOn();
1026     ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
1027   }
1028
1029   if (stateChange || modifiedHyp)
1030     ComputeStateEngine(MODIF_ALGO_STATE);
1031
1032   return ret;
1033 }
1034
1035 //=======================================================================
1036 //function : IsConform
1037 //purpose  : check if a conform mesh will be produced by the Algo
1038 //=======================================================================
1039
1040 bool SMESH_subMesh::IsConform(const SMESH_Algo* theAlgo)
1041 {
1042 //  MESSAGE( "SMESH_subMesh::IsConform" );
1043   if ( !theAlgo ) return false;
1044
1045   // Suppose that theAlgo is applicable to _subShape, do not check it here
1046   //if ( !IsApplicableHypotesis( theAlgo )) return false;
1047
1048   // check only algo that doesn't NeedDescretBoundary(): because mesh made
1049   // on a sub-shape will be ignored by theAlgo
1050   if ( theAlgo->NeedDescretBoundary() ||
1051        !theAlgo->OnlyUnaryInput() ) // all adjacent shapes will be meshed by this algo?
1052     return true;
1053
1054   SMESH_Gen* gen =_father->GetGen();
1055
1056   // only local algo is to be checked
1057   //if ( gen->IsGlobalHypothesis( theAlgo, *_father ))
1058   if ( _subShape.ShapeType() == _father->GetMeshDS()->ShapeToMesh().ShapeType() )
1059     return true;
1060
1061   // check algo attached to adjacent shapes
1062
1063   // loop on one level down sub-meshes
1064   TopoDS_Iterator itsub( _subShape );
1065   for (; itsub.More(); itsub.Next())
1066   {
1067     // loop on adjacent subShapes
1068     TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( itsub.Value() ));
1069     for (; it.More(); it.Next())
1070     {
1071       const TopoDS_Shape& adjacent = it.Value();
1072       if ( _subShape.IsSame( adjacent )) continue;
1073       if ( adjacent.ShapeType() != _subShape.ShapeType())
1074         break;
1075
1076       // check algo attached to smAdjacent
1077       SMESH_Algo * algo = gen->GetAlgo((*_father), adjacent);
1078       if (algo &&
1079           !algo->NeedDescretBoundary() &&
1080           algo->OnlyUnaryInput())
1081         return false; // NOT CONFORM MESH WILL BE PRODUCED
1082     }
1083   }
1084
1085   return true;
1086 }
1087
1088 //=============================================================================
1089 /*!
1090  *
1091  */
1092 //=============================================================================
1093
1094 void SMESH_subMesh::SetAlgoState(int state)
1095 {
1096   _algoState = state;
1097 }
1098
1099 //=============================================================================
1100 /*!
1101  *
1102  */
1103 //=============================================================================
1104 SMESH_Hypothesis::Hypothesis_Status
1105   SMESH_subMesh::SubMeshesAlgoStateEngine(int event,
1106                                           SMESH_Hypothesis * anHyp)
1107 {
1108   SMESH_Hypothesis::Hypothesis_Status ret = SMESH_Hypothesis::HYP_OK;
1109   //EAP: a wire (dim==1) should notify edges (dim==1)
1110   //EAP: int dim = SMESH_Gen::GetShapeDim(_subShape);
1111   //if (_subShape.ShapeType() < TopAbs_EDGE ) // wire,face etc
1112   {
1113     SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1114     while ( smIt->more() ) {
1115       SMESH_Hypothesis::Hypothesis_Status ret2 =
1116         smIt->next()->AlgoStateEngine(event, anHyp);
1117       if ( ret2 > ret )
1118         ret = ret2;
1119     }
1120   }
1121   return ret;
1122 }
1123
1124 //=============================================================================
1125 /*!
1126  *
1127  */
1128 //=============================================================================
1129
1130 void SMESH_subMesh::CleanDependsOn()
1131 {
1132   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1133   while ( smIt->more() )
1134     smIt->next()->ComputeStateEngine(CLEAN);
1135 }
1136
1137 //=============================================================================
1138 /*!
1139  *
1140  */
1141 //=============================================================================
1142
1143 void SMESH_subMesh::DumpAlgoState(bool isMain)
1144 {
1145         int dim = SMESH_Gen::GetShapeDim(_subShape);
1146 //   if (dim < 1) return;
1147         if (isMain)
1148         {
1149                 const map < int, SMESH_subMesh * >&subMeshes = DependsOn();
1150
1151                 map < int, SMESH_subMesh * >::const_iterator itsub;
1152                 for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++)
1153                 {
1154                         SMESH_subMesh *sm = (*itsub).second;
1155                         sm->DumpAlgoState(false);
1156                 }
1157         }
1158         int type = _subShape.ShapeType();
1159         MESSAGE("dim = " << dim << " type of shape " << type);
1160         switch (_algoState)
1161         {
1162         case NO_ALGO:
1163                 MESSAGE(" AlgoState = NO_ALGO");
1164                 break;
1165         case MISSING_HYP:
1166                 MESSAGE(" AlgoState = MISSING_HYP");
1167                 break;
1168         case HYP_OK:
1169                 MESSAGE(" AlgoState = HYP_OK");
1170                 break;
1171         }
1172         switch (_computeState)
1173         {
1174         case NOT_READY:
1175                 MESSAGE(" ComputeState = NOT_READY");
1176                 break;
1177         case READY_TO_COMPUTE:
1178                 MESSAGE(" ComputeState = READY_TO_COMPUTE");
1179                 break;
1180         case COMPUTE_OK:
1181                 MESSAGE(" ComputeState = COMPUTE_OK");
1182                 break;
1183         case FAILED_TO_COMPUTE:
1184                 MESSAGE(" ComputeState = FAILED_TO_COMPUTE");
1185                 break;
1186         }
1187 }
1188
1189 //================================================================================
1190 /*!
1191  * \brief Remove nodes and elements bound to submesh
1192   * \param subMesh - submesh containing nodes and elements
1193  */
1194 //================================================================================
1195
1196 static void cleanSubMesh( SMESH_subMesh * subMesh )
1197 {
1198   if (subMesh) {
1199     if (SMESHDS_SubMesh * subMeshDS = subMesh->GetSubMeshDS()) {
1200       SMESHDS_Mesh * meshDS = subMesh->GetFather()->GetMeshDS();
1201       SMDS_ElemIteratorPtr ite = subMeshDS->GetElements();
1202       while (ite->more()) {
1203         const SMDS_MeshElement * elt = ite->next();
1204         //MESSAGE( " RM elt: "<<elt->GetID()<<" ( "<<elt->NbNodes()<<" )" );
1205         //meshDS->RemoveElement(elt);
1206         meshDS->RemoveFreeElement(elt, subMeshDS);
1207       }
1208
1209       SMDS_NodeIteratorPtr itn = subMeshDS->GetNodes();
1210       while (itn->more()) {
1211         const SMDS_MeshNode * node = itn->next();
1212         //MESSAGE( " RM node: "<<node->GetID());
1213         if ( node->NbInverseElements() == 0 )
1214           meshDS->RemoveFreeNode(node, subMeshDS);
1215         else // for StdMeshers_CompositeSegment_1D: node in one submesh, edge in another
1216           meshDS->RemoveNode(node);
1217       }
1218     }
1219   }
1220 }
1221
1222 //=============================================================================
1223 /*!
1224  *
1225  */
1226 //=============================================================================
1227
1228 bool SMESH_subMesh::ComputeStateEngine(int event)
1229 {
1230   _computeError.reset();
1231
1232   //MESSAGE("SMESH_subMesh::ComputeStateEngine");
1233   //SCRUTE(_computeState);
1234   //SCRUTE(event);
1235
1236   if (_subShape.ShapeType() == TopAbs_VERTEX)
1237   {
1238     _computeState = READY_TO_COMPUTE;
1239     SMESHDS_SubMesh* smDS = GetSubMeshDS();
1240     if ( smDS && smDS->NbNodes() ) {
1241       if ( event == CLEAN ) {
1242         CleanDependants();
1243         cleanSubMesh( this );
1244       }
1245       else
1246         _computeState = COMPUTE_OK;
1247     }
1248     else if ( event == COMPUTE && !_alwaysComputed ) {
1249       const TopoDS_Vertex & V = TopoDS::Vertex( _subShape );
1250       gp_Pnt P = BRep_Tool::Pnt(V);
1251       if ( SMDS_MeshNode * n = _father->GetMeshDS()->AddNode(P.X(), P.Y(), P.Z()) ) {
1252         _father->GetMeshDS()->SetNodeOnVertex(n,_Id);
1253         _computeState = COMPUTE_OK;
1254       }
1255     }
1256     if ( event == MODIF_ALGO_STATE )
1257       CleanDependants();
1258     return true;
1259   }
1260   SMESH_Gen *gen = _father->GetGen();
1261   SMESH_Algo *algo = 0;
1262   bool ret = true;
1263   SMESH_Hypothesis::Hypothesis_Status hyp_status;
1264   //algo_state oldAlgoState = (algo_state) GetAlgoState();
1265
1266   switch (_computeState)
1267   {
1268
1269     // ----------------------------------------------------------------------
1270
1271   case NOT_READY:
1272     switch (event)
1273     {
1274     case MODIF_ALGO_STATE:
1275       algo = gen->GetAlgo((*_father), _subShape);
1276       if (algo && !algo->NeedDescretBoundary())
1277         CleanDependsOn(); // clean sub-meshes with event CLEAN
1278       if ( _algoState == HYP_OK )
1279         _computeState = READY_TO_COMPUTE;
1280       break;
1281     case COMPUTE:               // nothing to do
1282       break;
1283     case CLEAN:
1284       CleanDependants();
1285       RemoveSubMeshElementsAndNodes();
1286       break;
1287     case SUBMESH_COMPUTED:      // nothing to do
1288       break;
1289     case SUBMESH_RESTORED:
1290       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1291       break;
1292     case MESH_ENTITY_REMOVED:
1293       break;
1294     case CHECK_COMPUTE_STATE:
1295       if ( IsMeshComputed() )
1296         _computeState = COMPUTE_OK;
1297       break;
1298     default:
1299       ASSERT(0);
1300       break;
1301     }
1302     break;
1303
1304     // ----------------------------------------------------------------------
1305
1306   case READY_TO_COMPUTE:
1307     switch (event)
1308     {
1309     case MODIF_ALGO_STATE:
1310       _computeState = NOT_READY;
1311       algo = gen->GetAlgo((*_father), _subShape);
1312       if (algo)
1313       {
1314         if (!algo->NeedDescretBoundary())
1315           CleanDependsOn(); // clean sub-meshes with event CLEAN
1316         if ( _algoState == HYP_OK )
1317           _computeState = READY_TO_COMPUTE;
1318       }
1319       break;
1320     case COMPUTE:
1321       {
1322         algo = gen->GetAlgo((*_father), _subShape);
1323         ASSERT(algo);
1324         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1325         if (!ret)
1326         {
1327           MESSAGE("***** verify compute state *****");
1328           _computeState = NOT_READY;
1329           SetAlgoState(MISSING_HYP);
1330           break;
1331         }
1332         TopoDS_Shape shape = _subShape;
1333         // check submeshes needed
1334         if (_father->HasShapeToMesh() ) {
1335           bool subComputed = false;
1336           if (!algo->OnlyUnaryInput())
1337             shape = GetCollection( gen, algo, subComputed );
1338           else
1339             subComputed = SubMeshesComputed();
1340           ret = ( algo->NeedDescretBoundary() ? subComputed :
1341                   algo->SupportSubmeshes() ? true :
1342                   ( !subComputed || _father->IsNotConformAllowed() ));
1343           if (!ret) {
1344             _computeState = FAILED_TO_COMPUTE;
1345             if ( !algo->NeedDescretBoundary() )
1346               _computeError =
1347                 SMESH_ComputeError::New(COMPERR_BAD_INPUT_MESH,
1348                                         "Unexpected computed submesh",algo);
1349             break;
1350           }
1351         }
1352         // compute
1353 //         CleanDependants(); for "UseExisting_*D" algos
1354 //         RemoveSubMeshElementsAndNodes();
1355         ret = false;
1356         _computeState = FAILED_TO_COMPUTE;
1357         _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo);
1358         try {
1359 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1360           OCC_CATCH_SIGNALS;
1361 #endif
1362           algo->InitComputeError();
1363           MemoryReserve aMemoryReserve;
1364           SMDS_Mesh::CheckMemory();
1365           if ( !_father->HasShapeToMesh() ) // no shape
1366           {
1367             SMESH_MesherHelper helper( *_father );
1368             helper.SetSubShape( shape );
1369             helper.SetElementsOnShape( true );
1370             ret = algo->Compute(*_father, &helper );
1371           }
1372           else
1373           {
1374             ret = algo->Compute((*_father), shape);
1375           }
1376           if ( !_computeError || ( !ret && _computeError->IsOK() ) ) // algo can set _computeError of submesh
1377             _computeError = algo->GetComputeError();
1378         }
1379         catch ( std::bad_alloc& exc ) {
1380           MESSAGE("std::bad_alloc thrown inside algo->Compute()");
1381           if ( _computeError ) {
1382             _computeError->myName = COMPERR_MEMORY_PB;
1383             //_computeError->myComment = exc.what();
1384           }
1385           cleanSubMesh( this );
1386           throw exc;
1387         }
1388         catch ( Standard_OutOfMemory& exc ) {
1389           MESSAGE("Standard_OutOfMemory thrown inside algo->Compute()");
1390           if ( _computeError ) {
1391             _computeError->myName = COMPERR_MEMORY_PB;
1392             //_computeError->myComment = exc.what();
1393           }
1394           cleanSubMesh( this );
1395           throw std::bad_alloc();
1396         }
1397         catch (Standard_Failure& ex) {
1398           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1399           _computeError->myName    = COMPERR_OCC_EXCEPTION;
1400           _computeError->myComment += ex.DynamicType()->Name();
1401           if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) {
1402             _computeError->myComment += ": ";
1403             _computeError->myComment += ex.GetMessageString();
1404           }
1405         }
1406         catch ( SALOME_Exception& S_ex ) {
1407           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1408           _computeError->myName    = COMPERR_SLM_EXCEPTION;
1409           _computeError->myComment = S_ex.what();
1410         }
1411         catch ( std::exception& exc ) {
1412           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1413           _computeError->myName    = COMPERR_STD_EXCEPTION;
1414           _computeError->myComment = exc.what();
1415         }
1416         catch ( ... ) {
1417           if ( _computeError )
1418             _computeError->myName = COMPERR_EXCEPTION;
1419           else
1420             ret = false;
1421         }
1422         if (ret && !_alwaysComputed && shape == _subShape) { // check if anything was built
1423           ret = ( GetSubMeshDS() && ( GetSubMeshDS()->NbElements() || GetSubMeshDS()->NbNodes() ));
1424         }
1425         bool isComputeErrorSet = !CheckComputeError( algo, shape );
1426         if (!ret && !isComputeErrorSet)
1427         {
1428           // Set _computeError
1429           if ( !_computeError )
1430             _computeError = SMESH_ComputeError::New();
1431           if ( _computeError->IsOK() )
1432             _computeError->myName = COMPERR_ALGO_FAILED;
1433           _computeState = FAILED_TO_COMPUTE;
1434         }
1435         if (ret)
1436         {
1437           _computeError.reset();
1438         }
1439         UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
1440       }
1441       break;
1442     case CLEAN:
1443       CleanDependants();
1444       RemoveSubMeshElementsAndNodes();
1445       _computeState = NOT_READY;
1446       algo = gen->GetAlgo((*_father), _subShape);
1447       if (algo)
1448       {
1449         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1450         if (ret)
1451           _computeState = READY_TO_COMPUTE;
1452         else
1453           SetAlgoState(MISSING_HYP);
1454       }
1455       break;
1456     case SUBMESH_COMPUTED:      // nothing to do
1457       break;
1458     case SUBMESH_RESTORED:
1459       // check if a mesh is already computed that may
1460       // happen after retrieval from a file
1461       ComputeStateEngine( CHECK_COMPUTE_STATE );
1462       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1463       algo = gen->GetAlgo(*_father, _subShape);
1464       if (algo) algo->SubmeshRestored( this );
1465       break;
1466     case MESH_ENTITY_REMOVED:
1467       break;
1468     case CHECK_COMPUTE_STATE:
1469       if ( IsMeshComputed() )
1470         _computeState = COMPUTE_OK;
1471       break;
1472     default:
1473       ASSERT(0);
1474       break;
1475     }
1476     break;
1477
1478     // ----------------------------------------------------------------------
1479
1480   case COMPUTE_OK:
1481     switch (event)
1482     {
1483     case MODIF_ALGO_STATE:
1484       ComputeStateEngine( CLEAN );
1485       algo = gen->GetAlgo((*_father), _subShape);
1486       if (algo && !algo->NeedDescretBoundary())
1487         CleanDependsOn(); // clean sub-meshes with event CLEAN
1488       break;
1489     case COMPUTE:               // nothing to do
1490       break;
1491     case CLEAN:
1492       CleanDependants();  // clean sub-meshes, dependant on this one, with event CLEAN
1493       RemoveSubMeshElementsAndNodes();
1494       _computeState = NOT_READY;
1495       if ( _algoState == HYP_OK )
1496         _computeState = READY_TO_COMPUTE;
1497       break;
1498     case SUBMESH_COMPUTED:      // nothing to do
1499       break;
1500     case SUBMESH_RESTORED:
1501       ComputeStateEngine( CHECK_COMPUTE_STATE );
1502       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1503       algo = gen->GetAlgo(*_father, _subShape);
1504       if (algo) algo->SubmeshRestored( this );
1505       break;
1506     case MESH_ENTITY_REMOVED:
1507       UpdateDependantsState( CHECK_COMPUTE_STATE );
1508       ComputeStateEngine( CHECK_COMPUTE_STATE );
1509       ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
1510       break;
1511     case CHECK_COMPUTE_STATE:
1512       if ( !IsMeshComputed() )
1513         if (_algoState == HYP_OK)
1514           _computeState = READY_TO_COMPUTE;
1515         else
1516           _computeState = NOT_READY;
1517       break;
1518     default:
1519       ASSERT(0);
1520       break;
1521     }
1522     break;
1523
1524     // ----------------------------------------------------------------------
1525
1526   case FAILED_TO_COMPUTE:
1527     switch (event)
1528     {
1529     case MODIF_ALGO_STATE:
1530       algo = gen->GetAlgo((*_father), _subShape);
1531       if (algo && !algo->NeedDescretBoundary())
1532         CleanDependsOn(); // clean sub-meshes with event CLEAN
1533       if (_algoState == HYP_OK)
1534         _computeState = READY_TO_COMPUTE;
1535       else
1536         _computeState = NOT_READY;
1537       break;
1538     case COMPUTE:      // nothing to do
1539       break;
1540     case CLEAN:
1541       CleanDependants(); // submeshes dependent on me should be cleaned as well
1542       RemoveSubMeshElementsAndNodes();
1543       break;
1544     case SUBMESH_COMPUTED:      // allow retry compute
1545       if (_algoState == HYP_OK)
1546         _computeState = READY_TO_COMPUTE;
1547       else
1548         _computeState = NOT_READY;
1549       break;
1550     case SUBMESH_RESTORED:
1551       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1552       break;
1553     case MESH_ENTITY_REMOVED:
1554       break;
1555     case CHECK_COMPUTE_STATE:
1556       if ( IsMeshComputed() )
1557         _computeState = COMPUTE_OK;
1558       else
1559         if (_algoState == HYP_OK)
1560           _computeState = READY_TO_COMPUTE;
1561         else
1562           _computeState = NOT_READY;
1563       break;
1564     default:
1565       ASSERT(0);
1566       break;
1567     }
1568     break;
1569
1570     // ----------------------------------------------------------------------
1571   default:
1572     ASSERT(0);
1573     break;
1574   }
1575
1576   NotifyListenersOnEvent( event, COMPUTE_EVENT );
1577
1578   return ret;
1579 }
1580
1581
1582 //=============================================================================
1583 /*!
1584  *
1585  */
1586 //=============================================================================
1587
1588 bool SMESH_subMesh::Evaluate(MapShapeNbElems& aResMap)
1589 {
1590   _computeError.reset();
1591
1592   bool ret = true;
1593
1594   if (_subShape.ShapeType() == TopAbs_VERTEX) {
1595     std::vector<int> aVec(SMDSEntity_Last);
1596     for(int i= SMDSEntity_Node; i < SMDSEntity_Last; i++)
1597       aVec[i] = 0;
1598     aVec[SMDSEntity_Node] = 1;
1599     aResMap.insert(std::make_pair(this,aVec));
1600     return ret;
1601   }
1602
1603   SMESH_Gen *gen = _father->GetGen();
1604   SMESH_Algo *algo = 0;
1605   SMESH_Hypothesis::Hypothesis_Status hyp_status;
1606
1607   algo = gen->GetAlgo((*_father), _subShape);
1608   if(algo) {
1609     ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1610     if (!ret) return false;
1611
1612     TopoDS_Shape shape = _subShape;
1613
1614     _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo);
1615
1616     ret = algo->Evaluate((*_father), shape, aResMap);
1617   }
1618
1619   return ret;
1620 }
1621
1622
1623 //=======================================================================
1624 /*!
1625  * \brief Update compute_state by _computeError and send proper events to
1626  * dependent submeshes
1627   * \retval bool - true if _computeError is NOT set
1628  */
1629 //=======================================================================
1630
1631 bool SMESH_subMesh::CheckComputeError(SMESH_Algo* theAlgo, const TopoDS_Shape& theShape)
1632 {
1633   bool noErrors = true;
1634
1635   if ( !theShape.IsNull() )
1636   {
1637     // Check state of submeshes
1638     if ( !theAlgo->NeedDescretBoundary())
1639     {
1640       SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1641       while ( smIt->more() )
1642         if ( !smIt->next()->CheckComputeError( theAlgo ))
1643           noErrors = false;
1644     }
1645
1646     // Check state of neighbours
1647     if ( !theAlgo->OnlyUnaryInput() &&
1648          theShape.ShapeType() == TopAbs_COMPOUND &&
1649          !theShape.IsSame( _subShape ))
1650     {
1651       for (TopoDS_Iterator subIt( theShape ); subIt.More(); subIt.Next()) {
1652         SMESH_subMesh* sm = _father->GetSubMesh( subIt.Value() );
1653         if ( sm != this ) {
1654           if ( !sm->CheckComputeError( theAlgo, sm->GetSubShape() ))
1655             noErrors = false;
1656           UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
1657         }
1658       }
1659     }
1660   }
1661   {
1662     // Check my state
1663     if ( !_computeError || _computeError->IsOK() )
1664     {
1665       _computeState = COMPUTE_OK;
1666     }
1667     else
1668     {
1669       if ( !_computeError->myAlgo )
1670         _computeError->myAlgo = theAlgo;
1671
1672       // Show error
1673       SMESH_Comment text;
1674       text << theAlgo->GetName() << " failed on subshape #" << _Id << " with error ";
1675       if (_computeError->IsCommon() )
1676         text << _computeError->CommonName();
1677       else
1678         text << _computeError->myName;
1679       if ( _computeError->myComment.size() > 0 )
1680         text << " \"" << _computeError->myComment << "\"";
1681
1682 #ifdef _DEBUG_
1683       MESSAGE_BEGIN ( text );
1684       // Show vertices location of a failed shape
1685       TopTools_IndexedMapOfShape vMap;
1686       TopExp::MapShapes( _subShape, TopAbs_VERTEX, vMap );
1687       MESSAGE_ADD ( "Subshape vertices " << ( vMap.Extent()>10 ? "(first 10):" : ":") );
1688       for ( int iv = 1; iv <= vMap.Extent() && iv < 11; ++iv ) {
1689         gp_Pnt P( BRep_Tool::Pnt( TopoDS::Vertex( vMap( iv ) )));
1690         MESSAGE_ADD ( "#" << _father->GetMeshDS()->ShapeToIndex( vMap( iv )) << " "
1691                    << P.X() << " " << P.Y() << " " << P.Z() << " " );
1692       }
1693 #else
1694       INFOS( text );
1695 #endif
1696       _computeState = FAILED_TO_COMPUTE;
1697       noErrors = false;
1698     }
1699   }
1700   return noErrors;
1701 }
1702
1703 //=======================================================================
1704 //function : ApplyToCollection
1705 //purpose  : Apply theAlgo to all subshapes in theCollection
1706 //=======================================================================
1707
1708 bool SMESH_subMesh::ApplyToCollection (SMESH_Algo*         theAlgo,
1709                                        const TopoDS_Shape& theCollection)
1710 {
1711   MESSAGE("SMESH_subMesh::ApplyToCollection");
1712   ASSERT ( !theAlgo->NeedDescretBoundary() );
1713
1714   if ( _computeError )
1715     _computeError->myName = COMPERR_OK;
1716
1717   bool ok = theAlgo->Compute( *_father, theCollection );
1718
1719   // set _computeState of subshapes
1720   TopExp_Explorer anExplorer( theCollection, _subShape.ShapeType() );
1721   for ( ; anExplorer.More(); anExplorer.Next() )
1722   {
1723     if ( SMESH_subMesh* subMesh = _father->GetSubMeshContaining( anExplorer.Current() ))
1724     {
1725       bool localOK = subMesh->CheckComputeError( theAlgo );
1726       if ( !ok && localOK && !subMesh->IsMeshComputed() )
1727       {
1728         subMesh->_computeError = theAlgo->GetComputeError();
1729         if ( subMesh->_computeError->IsOK() )
1730           _computeError = SMESH_ComputeError::New(COMPERR_ALGO_FAILED);
1731         localOK = CheckComputeError( theAlgo );
1732       }
1733       if ( localOK )
1734         subMesh->UpdateDependantsState( SUBMESH_COMPUTED );
1735       subMesh->UpdateSubMeshState( localOK ? COMPUTE_OK : FAILED_TO_COMPUTE );
1736     }
1737   }
1738
1739   return true;
1740 }
1741
1742
1743 //=======================================================================
1744 //function : UpdateSubMeshState
1745 //purpose  :
1746 //=======================================================================
1747
1748 void SMESH_subMesh::UpdateSubMeshState(const compute_state theState)
1749 {
1750   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1751   while ( smIt->more() )
1752     smIt->next()->_computeState = theState;
1753 }
1754
1755 //=======================================================================
1756 //function : ComputeSubMeshStateEngine
1757 //purpose  :
1758 //=======================================================================
1759
1760 void SMESH_subMesh::ComputeSubMeshStateEngine(int event)
1761 {
1762   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1763   while ( smIt->more() )
1764     smIt->next()->ComputeStateEngine(event);
1765 }
1766
1767 //=======================================================================
1768 //function : UpdateDependantsState
1769 //purpose  :
1770 //=======================================================================
1771
1772 void SMESH_subMesh::UpdateDependantsState(const compute_event theEvent)
1773 {
1774   //MESSAGE("SMESH_subMesh::UpdateDependantsState");
1775   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1776   for (; it.More(); it.Next())
1777   {
1778     const TopoDS_Shape& ancestor = it.Value();
1779     SMESH_subMesh *aSubMesh =
1780       _father->GetSubMeshContaining(ancestor);
1781     if (aSubMesh)
1782       aSubMesh->ComputeStateEngine( theEvent );
1783   }
1784 }
1785
1786 //=============================================================================
1787 /*!
1788  *
1789  */
1790 //=============================================================================
1791
1792 void SMESH_subMesh::CleanDependants()
1793 {
1794   int dimToClean = SMESH_Gen::GetShapeDim( _subShape ) + 1;
1795
1796   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1797   for (; it.More(); it.Next())
1798   {
1799     const TopoDS_Shape& ancestor = it.Value();
1800     if ( SMESH_Gen::GetShapeDim( ancestor ) == dimToClean ) {
1801       // PAL8021. do not go upper than SOLID, else ComputeStateEngine(CLEAN)
1802       // will erase mesh on other shapes in a compound
1803       if ( ancestor.ShapeType() >= TopAbs_SOLID ) {
1804         SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor);
1805         if (aSubMesh)
1806           aSubMesh->ComputeStateEngine(CLEAN);
1807       }
1808     }
1809   }
1810 }
1811
1812 //=============================================================================
1813 /*!
1814  *
1815  */
1816 //=============================================================================
1817
1818 void SMESH_subMesh::RemoveSubMeshElementsAndNodes()
1819 {
1820   //SCRUTE(_subShape.ShapeType());
1821
1822   cleanSubMesh( this );
1823
1824   // algo may bind a submesh not to _subShape, eg 3D algo
1825   // sets nodes on SHELL while _subShape may be SOLID
1826
1827   int dim = SMESH_Gen::GetShapeDim( _subShape );
1828   int type = _subShape.ShapeType() + 1;
1829   for ( ; type <= TopAbs_EDGE; type++) {
1830     if ( dim == SMESH_Gen::GetShapeDim( (TopAbs_ShapeEnum) type ))
1831     {
1832       TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type );
1833       for ( ; exp.More(); exp.Next() )
1834         cleanSubMesh( _father->GetSubMeshContaining( exp.Current() ));
1835     }
1836     else
1837       break;
1838   }
1839 }
1840
1841 //=======================================================================
1842 //function : GetCollection
1843 //purpose  : return a shape containing all sub-shapes of the MainShape that can be
1844 //           meshed at once along with _subShape
1845 //=======================================================================
1846
1847 TopoDS_Shape SMESH_subMesh::GetCollection(SMESH_Gen * theGen,
1848                                           SMESH_Algo* theAlgo,
1849                                           bool &      theSubComputed)
1850 {
1851   MESSAGE("SMESH_subMesh::GetCollection");
1852
1853   theSubComputed = SubMeshesComputed();
1854
1855   TopoDS_Shape mainShape = _father->GetMeshDS()->ShapeToMesh();
1856
1857   if ( mainShape.IsSame( _subShape ))
1858     return _subShape;
1859
1860   const bool ignoreAuxiliaryHyps = false;
1861   list<const SMESHDS_Hypothesis*> aUsedHyp =
1862     theAlgo->GetUsedHypothesis( *_father, _subShape, ignoreAuxiliaryHyps ); // copy
1863
1864   // put in a compound all shapes with the same hypothesis assigned
1865   // and a good ComputState
1866
1867   TopoDS_Compound aCompound;
1868   BRep_Builder aBuilder;
1869   aBuilder.MakeCompound( aCompound );
1870
1871   TopExp_Explorer anExplorer( mainShape, _subShape.ShapeType() );
1872   for ( ; anExplorer.More(); anExplorer.Next() )
1873   {
1874     const TopoDS_Shape& S = anExplorer.Current();
1875     SMESH_subMesh* subMesh = _father->GetSubMesh( S );
1876     if ( subMesh == this )
1877     {
1878       aBuilder.Add( aCompound, S );
1879     }
1880     else if ( subMesh->GetComputeState() == READY_TO_COMPUTE )
1881     {
1882       SMESH_Algo* anAlgo = theGen->GetAlgo( *_father, S );
1883       if (strcmp( anAlgo->GetName(), theAlgo->GetName()) == 0 && // same algo
1884           anAlgo->GetUsedHypothesis( *_father, S, ignoreAuxiliaryHyps ) == aUsedHyp) // same hyps
1885         aBuilder.Add( aCompound, S );
1886       if ( !subMesh->SubMeshesComputed() )
1887         theSubComputed = false;
1888     }
1889   }
1890
1891   return aCompound;
1892 }
1893
1894 //=======================================================================
1895 //function : GetSimilarAttached
1896 //purpose  : return a hypothesis attached to theShape.
1897 //           If theHyp is provided, similar but not same hypotheses
1898 //           is returned; else only applicable ones having theHypType
1899 //           is returned
1900 //=======================================================================
1901
1902 const SMESH_Hypothesis* SMESH_subMesh::GetSimilarAttached(const TopoDS_Shape&      theShape,
1903                                                           const SMESH_Hypothesis * theHyp,
1904                                                           const int                theHypType)
1905 {
1906   SMESH_HypoFilter hypoKind;
1907   hypoKind.Init( hypoKind.HasType( theHyp ? theHyp->GetType() : theHypType ));
1908   if ( theHyp ) {
1909     hypoKind.And   ( hypoKind.HasDim( theHyp->GetDim() ));
1910     hypoKind.AndNot( hypoKind.Is( theHyp ));
1911     if ( theHyp->IsAuxiliary() )
1912       hypoKind.And( hypoKind.HasName( theHyp->GetName() ));
1913     else
1914       hypoKind.AndNot( hypoKind.IsAuxiliary());
1915   }
1916   else {
1917     hypoKind.And( hypoKind.IsApplicableTo( theShape ));
1918   }
1919
1920   return _father->GetHypothesis( theShape, hypoKind, false );
1921 }
1922
1923 //=======================================================================
1924 //function : CheckConcurentHypothesis
1925 //purpose  : check if there are several applicable hypothesis attached to
1926 //           ancestors
1927 //=======================================================================
1928
1929 SMESH_Hypothesis::Hypothesis_Status
1930   SMESH_subMesh::CheckConcurentHypothesis (const int theHypType)
1931 {
1932   MESSAGE ("SMESH_subMesh::CheckConcurentHypothesis");
1933
1934   // is there local hypothesis on me?
1935   if ( GetSimilarAttached( _subShape, 0, theHypType ) )
1936     return SMESH_Hypothesis::HYP_OK;
1937
1938
1939   TopoDS_Shape aPrevWithHyp;
1940   const SMESH_Hypothesis* aPrevHyp = 0;
1941   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1942   for (; it.More(); it.Next())
1943   {
1944     const TopoDS_Shape& ancestor = it.Value();
1945     const SMESH_Hypothesis* hyp = GetSimilarAttached( ancestor, 0, theHypType );
1946     if ( hyp )
1947     {
1948       if ( aPrevWithHyp.IsNull() || aPrevWithHyp.IsSame( ancestor ))
1949       {
1950         aPrevWithHyp = ancestor;
1951         aPrevHyp     = hyp;
1952       }
1953       else if ( aPrevWithHyp.ShapeType() == ancestor.ShapeType() && aPrevHyp != hyp )
1954         return SMESH_Hypothesis::HYP_CONCURENT;
1955       else
1956         return SMESH_Hypothesis::HYP_OK;
1957     }
1958   }
1959   return SMESH_Hypothesis::HYP_OK;
1960 }
1961
1962 //================================================================================
1963 /*!
1964  * \brief Sets an event listener and its data to a submesh
1965  * \param listener - the listener to store
1966  * \param data - the listener data to store
1967  * \param where - the submesh to store the listener and it's data
1968  * \param deleteListener - if true then the listener will be deleted as
1969  *        it is removed from where submesh
1970  * 
1971  * It remembers the submesh where it puts the listener in order to delete
1972  * them when HYP_OK algo_state is lost
1973  * After being set, event listener is notified on each event of where submesh.
1974  */
1975 //================================================================================
1976
1977 void SMESH_subMesh::SetEventListener(EventListener*     listener,
1978                                      EventListenerData* data,
1979                                      SMESH_subMesh*     where)
1980 {
1981   if ( listener && where ) {
1982     where->SetEventListener( listener, data );
1983     myOwnListeners.push_back( make_pair( where, listener ));
1984   }
1985 }
1986
1987 //================================================================================
1988 /*!
1989  * \brief Sets an event listener and its data to a submesh
1990  * \param listener - the listener to store
1991  * \param data - the listener data to store
1992  * 
1993  * After being set, event listener is notified on each event of a submesh.
1994  */
1995 //================================================================================
1996
1997 void SMESH_subMesh::SetEventListener(EventListener* listener, EventListenerData* data)
1998 {
1999   map< EventListener*, EventListenerData* >::iterator l_d =
2000     myEventListeners.find( listener );
2001   if ( l_d != myEventListeners.end() ) {
2002     EventListenerData* curData = l_d->second;
2003     if ( curData && curData != data && curData->IsDeletable() )
2004       delete curData;
2005     l_d->second = data;
2006   }
2007   else 
2008     myEventListeners.insert( make_pair( listener, data ));
2009 }
2010
2011 //================================================================================
2012 /*!
2013  * \brief Return an event listener data
2014  * \param listener - the listener whose data is
2015  * \retval EventListenerData* - found data, maybe NULL
2016  */
2017 //================================================================================
2018
2019 EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener) const
2020 {
2021   map< EventListener*, EventListenerData* >::const_iterator l_d =
2022     myEventListeners.find( listener );
2023   if ( l_d != myEventListeners.end() )
2024     return l_d->second;
2025   return 0;
2026 }
2027
2028 //================================================================================
2029 /*!
2030  * \brief Notify stored event listeners on the occured event
2031  * \param event - algo_event or compute_event itself
2032  * \param eventType - algo_event or compute_event
2033  * \param subMesh - the submesh where the event occures
2034  * \param data - listener data stored in the subMesh
2035  * \param hyp - hypothesis, if eventType is algo_event
2036  */
2037 //================================================================================
2038
2039 void SMESH_subMesh::NotifyListenersOnEvent( const int         event,
2040                                             const event_type  eventType,
2041                                             SMESH_Hypothesis* hyp)
2042 {
2043   map< EventListener*, EventListenerData* >::iterator l_d = myEventListeners.begin();
2044   for ( ; l_d != myEventListeners.end(); ++l_d )
2045     l_d->first->ProcessEvent( event, eventType, this, l_d->second, hyp );
2046 }
2047
2048 //================================================================================
2049 /*!
2050  * \brief Unregister the listener and delete listener's data
2051  * \param listener - the event listener
2052  */
2053 //================================================================================
2054
2055 void SMESH_subMesh::DeleteEventListener(EventListener* listener)
2056 {
2057   map< EventListener*, EventListenerData* >::iterator l_d =
2058     myEventListeners.find( listener );
2059   if ( l_d != myEventListeners.end() ) {
2060     if ( l_d->first  && l_d->first->IsDeletable() )  delete l_d->first;
2061     if ( l_d->second && l_d->second->IsDeletable() ) delete l_d->second;
2062     myEventListeners.erase( l_d );
2063   }
2064 }
2065
2066 //================================================================================
2067 /*!
2068  * \brief Delete event listeners depending on algo of this submesh
2069  */
2070 //================================================================================
2071
2072 void SMESH_subMesh::DeleteOwnListeners()
2073 {
2074   list< pair< SMESH_subMesh*, EventListener* > >::iterator sm_l;
2075   for ( sm_l = myOwnListeners.begin(); sm_l != myOwnListeners.end(); ++sm_l)
2076     sm_l->first->DeleteEventListener( sm_l->second );
2077   myOwnListeners.clear();
2078 }
2079
2080 //================================================================================
2081 /*!
2082  * \brief Do something on a certain event
2083  * \param event - algo_event or compute_event itself
2084  * \param eventType - algo_event or compute_event
2085  * \param subMesh - the submesh where the event occures
2086  * \param data - listener data stored in the subMesh
2087  * \param hyp - hypothesis, if eventType is algo_event
2088  * 
2089  * The base implementation translates CLEAN event to the subMesh
2090  * stored in listener data. Also it sends SUBMESH_COMPUTED event in case of
2091  * successful COMPUTE event.
2092  */
2093 //================================================================================
2094
2095 void SMESH_subMeshEventListener::ProcessEvent(const int          event,
2096                                               const int          eventType,
2097                                               SMESH_subMesh*     subMesh,
2098                                               EventListenerData* data,
2099                                               const SMESH_Hypothesis*  /*hyp*/)
2100 {
2101   if ( data && !data->mySubMeshes.empty() &&
2102        eventType == SMESH_subMesh::COMPUTE_EVENT)
2103   {
2104     ASSERT( data->mySubMeshes.front() != subMesh );
2105     list<SMESH_subMesh*>::iterator smIt = data->mySubMeshes.begin();
2106     list<SMESH_subMesh*>::iterator smEnd = data->mySubMeshes.end();
2107     switch ( event ) {
2108     case SMESH_subMesh::CLEAN:
2109       for ( ; smIt != smEnd; ++ smIt)
2110         (*smIt)->ComputeStateEngine( event );
2111       break;
2112     case SMESH_subMesh::COMPUTE:
2113       if ( subMesh->GetComputeState() == SMESH_subMesh::COMPUTE_OK )
2114         for ( ; smIt != smEnd; ++ smIt)
2115           (*smIt)->ComputeStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
2116       break;
2117     default:;
2118     }
2119   }
2120 }
2121
2122 namespace {
2123
2124   //================================================================================
2125   /*!
2126    * \brief Iterator over submeshes and optionally prepended or appended one
2127    */
2128   //================================================================================
2129
2130   struct _Iterator : public SMDS_Iterator<SMESH_subMesh*>
2131   {
2132     _Iterator(SMDS_Iterator<SMESH_subMesh*>* subIt,
2133               SMESH_subMesh*                 prepend,
2134               SMESH_subMesh*                 append): myIt(subIt),myAppend(append)
2135     {
2136       myCur = prepend ? prepend : myIt->more() ? myIt->next() : append;
2137       if ( myCur == append ) append = 0;
2138     }
2139     /// Return true if and only if there are other object in this iterator
2140     virtual bool more()
2141     {
2142       return myCur;
2143     }
2144     /// Return the current object and step to the next one
2145     virtual SMESH_subMesh* next()
2146     {
2147       SMESH_subMesh* res = myCur;
2148       if ( myIt->more() ) { myCur = myIt->next(); }
2149       else                { myCur = myAppend; myAppend = 0; }
2150       return res;
2151     }
2152     /// ~
2153     ~_Iterator()
2154     { delete myIt; }
2155     ///
2156     SMESH_subMesh                 *myAppend, *myCur;
2157     SMDS_Iterator<SMESH_subMesh*> *myIt;
2158   };
2159 }
2160
2161 //================================================================================
2162 /*!
2163  * \brief  Return iterator on the submeshes this one depends on
2164   * \param includeSelf - this submesh to be returned also
2165   * \param reverse - if true, complex shape submeshes go first
2166  */
2167 //================================================================================
2168
2169 SMESH_subMeshIteratorPtr SMESH_subMesh::getDependsOnIterator(const bool includeSelf,
2170                                                              const bool reverse)
2171 {
2172   SMESH_subMesh *prepend=0, *append=0;
2173   if ( includeSelf ) {
2174     if ( reverse ) prepend = this;
2175     else            append = this;
2176   }
2177   typedef map < int, SMESH_subMesh * > TMap;
2178   if ( reverse )
2179   {
2180     return SMESH_subMeshIteratorPtr
2181       ( new _Iterator( new SMDS_mapReverseIterator<TMap>( DependsOn() ), prepend, append ));
2182   }
2183   {
2184     return SMESH_subMeshIteratorPtr
2185       ( new _Iterator( new SMDS_mapIterator<TMap>( DependsOn() ), prepend, append ));
2186   }
2187 }