Salome HOME
Merge from BR_V5_DEV 16Feb09
[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 //  $Header$
27 //
28 #include "SMESH_subMesh.hxx"
29
30 #include "SMESH_Algo.hxx"
31 #include "SMESH_Gen.hxx"
32 #include "SMESH_HypoFilter.hxx"
33 #include "SMESH_Hypothesis.hxx"
34 #include "SMESH_Mesh.hxx"
35 #include "SMESH_MesherHelper.hxx"
36 #include "SMESH_subMeshEventListener.hxx"
37 #include "SMESH_Comment.hxx"
38 #include "SMDS_SetIterator.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
613   bool isApplicableHyp = IsApplicableHypotesis( anHyp );
614
615   if (event == ADD_ALGO || event == ADD_FATHER_ALGO)
616   {
617     // -------------------------------------------
618     // check if a shape needed by algo is present
619     // -------------------------------------------
620     algo = static_cast< SMESH_Algo* >( anHyp );
621     if ( !_father->HasShapeToMesh() && algo->NeedShape() )
622       return SMESH_Hypothesis::HYP_NEED_SHAPE;
623     // ----------------------
624     // check mesh conformity
625     // ----------------------
626     if (isApplicableHyp && !_father->IsNotConformAllowed() && !IsConform( algo ))
627       return SMESH_Hypothesis::HYP_NOTCONFORM;
628   }
629
630   // ----------------------------------
631   // add a hypothesis to DS if possible
632   // ----------------------------------
633   if (event == ADD_HYP || event == ADD_ALGO)
634   {
635     if ( ! CanAddHypothesis( anHyp )) // check dimension
636       return SMESH_Hypothesis::HYP_BAD_DIM;
637
638     if ( /*!anHyp->IsAuxiliary() &&*/ GetSimilarAttached( _subShape, anHyp ) )
639       return SMESH_Hypothesis::HYP_ALREADY_EXIST;
640
641     if ( !meshDS->AddHypothesis(_subShape, anHyp))
642       return SMESH_Hypothesis::HYP_ALREADY_EXIST;
643   }
644
645   // --------------------------
646   // remove a hypothesis from DS
647   // --------------------------
648   if (event == REMOVE_HYP || event == REMOVE_ALGO)
649   {
650     if (!meshDS->RemoveHypothesis(_subShape, anHyp))
651       return SMESH_Hypothesis::HYP_OK; // nothing changes
652
653     if (event == REMOVE_ALGO)
654     {
655       algo = dynamic_cast<SMESH_Algo*> (anHyp);
656       if (!algo->NeedDescretBoundary())
657       {
658         // clean all mesh in the tree of the current submesh;
659         // we must perform it now because later
660         // we will have no information about the type of the removed algo
661         CleanDependants();
662         ComputeStateEngine( CLEAN );
663         CleanDependsOn();
664         ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
665       }
666     }
667   }
668
669   // ------------------
670   // analyse algo state
671   // ------------------
672   if (!isApplicableHyp)
673     return ret; // not applicable hypotheses do not change algo state
674
675   switch (_algoState)
676   {
677
678     // ----------------------------------------------------------------------
679
680   case NO_ALGO:
681     switch (event) {
682     case ADD_HYP:
683       break;
684     case ADD_ALGO: {
685       algo = gen->GetAlgo((*_father), _subShape);
686       ASSERT(algo);
687       if (algo->CheckHypothesis((*_father),_subShape, aux_ret))
688         SetAlgoState(HYP_OK);
689       else if ( algo->IsStatusFatal( aux_ret )) {
690         meshDS->RemoveHypothesis(_subShape, anHyp);
691         ret = aux_ret;
692       }
693       else
694         SetAlgoState(MISSING_HYP);
695       break;
696     }
697     case REMOVE_HYP:
698     case REMOVE_ALGO:
699     case ADD_FATHER_HYP:
700       break;
701     case ADD_FATHER_ALGO: {    // Algo just added in father
702       algo = gen->GetAlgo((*_father), _subShape);
703       ASSERT(algo);
704       if ( algo == anHyp ) {
705         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret))
706           SetAlgoState(HYP_OK);
707         else
708           SetAlgoState(MISSING_HYP);
709       }
710       break;
711     }
712     case REMOVE_FATHER_HYP:
713       break;
714     case REMOVE_FATHER_ALGO: {
715       algo = gen->GetAlgo((*_father), _subShape);
716       if (algo)
717       {
718         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
719             SetAlgoState(HYP_OK);
720         else
721           SetAlgoState(MISSING_HYP);
722       }
723       break;
724     }
725     case MODIF_HYP: break;
726     default:
727       ASSERT(0);
728       break;
729     }
730     break;
731
732     // ----------------------------------------------------------------------
733
734   case MISSING_HYP:
735     switch (event)
736     {
737     case ADD_HYP: {
738       algo = gen->GetAlgo((*_father), _subShape);
739       ASSERT(algo);
740       if ( algo->CheckHypothesis((*_father),_subShape, ret ))
741         SetAlgoState(HYP_OK);
742       if (SMESH_Hypothesis::IsStatusFatal( ret ))
743         meshDS->RemoveHypothesis(_subShape, anHyp);
744       else if (!_father->IsUsedHypothesis( anHyp, this ))
745       {
746         meshDS->RemoveHypothesis(_subShape, anHyp);
747         ret = SMESH_Hypothesis::HYP_INCOMPATIBLE;
748       }
749       break;
750     }
751     case ADD_ALGO: {           //already existing algo : on father ?
752       algo = gen->GetAlgo((*_father), _subShape);
753       ASSERT(algo);
754       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))// ignore hyp status
755         SetAlgoState(HYP_OK);
756       else if ( algo->IsStatusFatal( aux_ret )) {
757         meshDS->RemoveHypothesis(_subShape, anHyp);
758         ret = aux_ret;
759       }
760       else
761         SetAlgoState(MISSING_HYP);
762       break;
763     }
764     case REMOVE_HYP:
765       break;
766     case REMOVE_ALGO: {        // perhaps a father algo applies ?
767       algo = gen->GetAlgo((*_father), _subShape);
768       if (algo == NULL)  // no more algo applying on subShape...
769       {
770         SetAlgoState(NO_ALGO);
771       }
772       else
773       {
774         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
775           SetAlgoState(HYP_OK);
776         else
777           SetAlgoState(MISSING_HYP);
778       }
779       break;
780     }
781     case MODIF_HYP: // assigned hypothesis value may become good
782     case ADD_FATHER_HYP: {
783       algo = gen->GetAlgo((*_father), _subShape);
784       ASSERT(algo);
785       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
786         SetAlgoState(HYP_OK);
787       else
788         SetAlgoState(MISSING_HYP);
789       break;
790     }
791     case ADD_FATHER_ALGO: { // new father algo
792       algo = gen->GetAlgo((*_father), _subShape);
793       ASSERT( algo );
794       if ( algo == anHyp ) {
795         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
796           SetAlgoState(HYP_OK);
797         else
798           SetAlgoState(MISSING_HYP);
799       }
800       break;
801     }
802     case REMOVE_FATHER_HYP:    // nothing to do
803       break;
804     case REMOVE_FATHER_ALGO: {
805       algo = gen->GetAlgo((*_father), _subShape);
806       if (algo == NULL)  // no more applying algo on father
807       {
808         SetAlgoState(NO_ALGO);
809       }
810       else
811       {
812         if ( algo->CheckHypothesis((*_father),_subShape , aux_ret ))
813           SetAlgoState(HYP_OK);
814         else
815           SetAlgoState(MISSING_HYP);
816       }
817       break;
818     }
819     default:
820       ASSERT(0);
821       break;
822     }
823     break;
824
825     // ----------------------------------------------------------------------
826
827   case HYP_OK:
828     switch (event)
829     {
830     case ADD_HYP: {
831       algo = gen->GetAlgo((*_father), _subShape);
832       ASSERT(algo);
833       if (!algo->CheckHypothesis((*_father),_subShape, ret ))
834       {
835         if ( !SMESH_Hypothesis::IsStatusFatal( ret ))
836           // ret should be fatal: anHyp was not added
837           ret = SMESH_Hypothesis::HYP_INCOMPATIBLE;
838       }
839       else if (!_father->IsUsedHypothesis(  anHyp, this ))
840         ret = SMESH_Hypothesis::HYP_INCOMPATIBLE;
841
842       if (SMESH_Hypothesis::IsStatusFatal( ret ))
843       {
844         MESSAGE("do not add extra hypothesis");
845         meshDS->RemoveHypothesis(_subShape, anHyp);
846       }
847       else
848       {
849         modifiedHyp = true;
850       }
851       break;
852     }
853     case ADD_ALGO: {           //already existing algo : on father ?
854       algo = gen->GetAlgo((*_father), _subShape);
855       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
856         // check if algo changes
857         SMESH_HypoFilter f;
858         f.Init(   SMESH_HypoFilter::IsAlgo() );
859         f.And(    SMESH_HypoFilter::IsApplicableTo( _subShape ));
860         f.AndNot( SMESH_HypoFilter::Is( algo ));
861         const SMESH_Hypothesis * prevAlgo = _father->GetHypothesis( _subShape, f, true );
862         if (prevAlgo &&
863             string(algo->GetName()) != string(prevAlgo->GetName()) )
864           modifiedHyp = true;
865       }
866       else
867         SetAlgoState(MISSING_HYP);
868       break;
869     }
870     case REMOVE_HYP: {
871       algo = gen->GetAlgo((*_father), _subShape);
872       ASSERT(algo);
873       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
874         SetAlgoState(HYP_OK);
875       else
876         SetAlgoState(MISSING_HYP);
877       modifiedHyp = true;
878       break;
879     }
880     case REMOVE_ALGO: {         // perhaps a father algo applies ?
881       algo = gen->GetAlgo((*_father), _subShape);
882       if (algo == NULL)   // no more algo applying on subShape...
883       {
884         SetAlgoState(NO_ALGO);
885       }
886       else
887       {
888         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
889           // check if algo remains
890           if ( anHyp != algo && strcmp( anHyp->GetName(), algo->GetName()) )
891             modifiedHyp = true;
892         }
893         else
894           SetAlgoState(MISSING_HYP);
895       }
896       break;
897     }
898     case MODIF_HYP: // hypothesis value may become bad
899     case ADD_FATHER_HYP: {  // new father hypothesis ?
900       algo = gen->GetAlgo((*_father), _subShape);
901       ASSERT(algo);
902       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
903       {
904         if (_father->IsUsedHypothesis( anHyp, this )) // new Hyp
905           modifiedHyp = true;
906       }
907       else
908         SetAlgoState(MISSING_HYP);
909       break;
910     }
911     case ADD_FATHER_ALGO: {
912       algo = gen->GetAlgo((*_father), _subShape);
913       if ( algo == anHyp ) { // a new algo on father
914         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
915           // check if algo changes
916           SMESH_HypoFilter f;
917           f.Init(   SMESH_HypoFilter::IsAlgo() );
918           f.And(    SMESH_HypoFilter::IsApplicableTo( _subShape ));
919           f.AndNot( SMESH_HypoFilter::Is( algo ));
920           const SMESH_Hypothesis* prevAlgo = _father->GetHypothesis( _subShape, f, true );
921           if (prevAlgo &&
922               string(algo->GetName()) != string(prevAlgo->GetName()) )
923             modifiedHyp = true;
924         }
925         else
926           SetAlgoState(MISSING_HYP);
927       }
928       break;
929     }
930     case REMOVE_FATHER_HYP: {
931       algo = gen->GetAlgo((*_father), _subShape);
932       ASSERT(algo);
933       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
934         // is there the same local hyp or maybe a new father algo applied?
935         if ( !GetSimilarAttached( _subShape, anHyp ) )
936           modifiedHyp = true;
937       }
938       else
939         SetAlgoState(MISSING_HYP);
940       break;
941     }
942     case REMOVE_FATHER_ALGO: {
943       algo = gen->GetAlgo((*_father), _subShape);
944       if (algo == NULL)  // no more applying algo on father
945       {
946         SetAlgoState(NO_ALGO);
947       }
948       else
949       {
950         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
951           // check if algo changes
952           if ( string(algo->GetName()) != string( anHyp->GetName()) )
953             modifiedHyp = true;
954         }
955         else
956           SetAlgoState(MISSING_HYP);
957       }
958       break;
959     }
960     default:
961       ASSERT(0);
962       break;
963     }
964     break;
965
966     // ----------------------------------------------------------------------
967
968   default:
969     ASSERT(0);
970     break;
971   }
972
973   // detect algorithm hiding
974   //
975   if ( ret == SMESH_Hypothesis::HYP_OK &&
976        ( event == ADD_ALGO || event == ADD_FATHER_ALGO ) &&
977        algo->GetName() == anHyp->GetName() )
978   {
979     // is algo hidden?
980     SMESH_Gen* gen = _father->GetGen();
981     TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
982     for ( ; ( ret == SMESH_Hypothesis::HYP_OK && it.More()); it.Next() ) {
983       if ( SMESH_Algo* upperAlgo = gen->GetAlgo( *_father, it.Value() ))
984         if ( !upperAlgo->NeedDescretBoundary() && !upperAlgo->SupportSubmeshes())
985           ret = SMESH_Hypothesis::HYP_HIDDEN_ALGO;
986     }
987     // is algo hiding?
988     if ( ret == SMESH_Hypothesis::HYP_OK &&
989          !algo->NeedDescretBoundary()    &&
990          !algo->SupportSubmeshes()) {
991       map<int, SMESH_subMesh*>::reverse_iterator i_sm = _mapDepend.rbegin();
992       for ( ; ( ret == SMESH_Hypothesis::HYP_OK && i_sm != _mapDepend.rend()) ; ++i_sm )
993         if ( gen->GetAlgo( *_father, i_sm->second->_subShape ))
994           ret = SMESH_Hypothesis::HYP_HIDING_ALGO;
995     }
996   }
997
998   bool stateChange = ( _algoState != oldAlgoState );
999
1000   if ( stateChange && _algoState == HYP_OK ) // hyp becomes OK
1001     algo->SetEventListener( this );
1002
1003   NotifyListenersOnEvent( event, ALGO_EVENT, anHyp );
1004
1005   if ( stateChange && oldAlgoState == HYP_OK ) { // hyp becomes KO
1006     DeleteOwnListeners();
1007     SetIsAlwaysComputed( false );
1008     if (_subShape.ShapeType() == TopAbs_VERTEX ) {
1009       // restore default states
1010       _algoState = HYP_OK;
1011       _computeState = READY_TO_COMPUTE;
1012     }
1013   }
1014
1015   if (stateChange || modifiedHyp)
1016     ComputeStateEngine(MODIF_ALGO_STATE);
1017
1018   return ret;
1019 }
1020
1021 //=======================================================================
1022 //function : IsConform
1023 //purpose  : check if a conform mesh will be produced by the Algo
1024 //=======================================================================
1025
1026 bool SMESH_subMesh::IsConform(const SMESH_Algo* theAlgo)
1027 {
1028 //  MESSAGE( "SMESH_subMesh::IsConform" );
1029   if ( !theAlgo ) return false;
1030
1031   // Suppose that theAlgo is applicable to _subShape, do not check it here
1032   //if ( !IsApplicableHypotesis( theAlgo )) return false;
1033
1034   // check only algo that doesn't NeedDescretBoundary(): because mesh made
1035   // on a sub-shape will be ignored by theAlgo
1036   if ( theAlgo->NeedDescretBoundary() ||
1037        !theAlgo->OnlyUnaryInput() ) // all adjacent shapes will be meshed by this algo?
1038     return true;
1039
1040   SMESH_Gen* gen =_father->GetGen();
1041
1042   // only local algo is to be checked
1043   //if ( gen->IsGlobalHypothesis( theAlgo, *_father ))
1044   if ( _subShape.ShapeType() == _father->GetMeshDS()->ShapeToMesh().ShapeType() )
1045     return true;
1046
1047   // check algo attached to adjacent shapes
1048
1049   // loop on one level down sub-meshes
1050   TopoDS_Iterator itsub( _subShape );
1051   for (; itsub.More(); itsub.Next())
1052   {
1053     // loop on adjacent subShapes
1054     TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( itsub.Value() ));
1055     for (; it.More(); it.Next())
1056     {
1057       const TopoDS_Shape& adjacent = it.Value();
1058       if ( _subShape.IsSame( adjacent )) continue;
1059       if ( adjacent.ShapeType() != _subShape.ShapeType())
1060         break;
1061
1062       // check algo attached to smAdjacent
1063       SMESH_Algo * algo = gen->GetAlgo((*_father), adjacent);
1064       if (algo &&
1065           !algo->NeedDescretBoundary() &&
1066           algo->OnlyUnaryInput())
1067         return false; // NOT CONFORM MESH WILL BE PRODUCED
1068     }
1069   }
1070
1071   return true;
1072 }
1073
1074 //=============================================================================
1075 /*!
1076  *
1077  */
1078 //=============================================================================
1079
1080 void SMESH_subMesh::SetAlgoState(int state)
1081 {
1082   _algoState = state;
1083 }
1084
1085 //=============================================================================
1086 /*!
1087  *
1088  */
1089 //=============================================================================
1090 SMESH_Hypothesis::Hypothesis_Status
1091   SMESH_subMesh::SubMeshesAlgoStateEngine(int event,
1092                                           SMESH_Hypothesis * anHyp)
1093 {
1094   SMESH_Hypothesis::Hypothesis_Status ret = SMESH_Hypothesis::HYP_OK;
1095   //EAP: a wire (dim==1) should notify edges (dim==1)
1096   //EAP: int dim = SMESH_Gen::GetShapeDim(_subShape);
1097   //if (_subShape.ShapeType() < TopAbs_EDGE ) // wire,face etc
1098   {
1099     SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1100     while ( smIt->more() ) {
1101       SMESH_Hypothesis::Hypothesis_Status ret2 =
1102         smIt->next()->AlgoStateEngine(event, anHyp);
1103       if ( ret2 > ret )
1104         ret = ret2;
1105     }
1106   }
1107   return ret;
1108 }
1109
1110 //=============================================================================
1111 /*!
1112  *
1113  */
1114 //=============================================================================
1115
1116 void SMESH_subMesh::CleanDependsOn()
1117 {
1118   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1119   while ( smIt->more() )
1120     smIt->next()->ComputeStateEngine(CLEAN);
1121 }
1122
1123 //=============================================================================
1124 /*!
1125  *
1126  */
1127 //=============================================================================
1128
1129 void SMESH_subMesh::DumpAlgoState(bool isMain)
1130 {
1131         int dim = SMESH_Gen::GetShapeDim(_subShape);
1132 //   if (dim < 1) return;
1133         if (isMain)
1134         {
1135                 const map < int, SMESH_subMesh * >&subMeshes = DependsOn();
1136
1137                 map < int, SMESH_subMesh * >::const_iterator itsub;
1138                 for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++)
1139                 {
1140                         SMESH_subMesh *sm = (*itsub).second;
1141                         sm->DumpAlgoState(false);
1142                 }
1143         }
1144         int type = _subShape.ShapeType();
1145         MESSAGE("dim = " << dim << " type of shape " << type);
1146         switch (_algoState)
1147         {
1148         case NO_ALGO:
1149                 MESSAGE(" AlgoState = NO_ALGO");
1150                 break;
1151         case MISSING_HYP:
1152                 MESSAGE(" AlgoState = MISSING_HYP");
1153                 break;
1154         case HYP_OK:
1155                 MESSAGE(" AlgoState = HYP_OK");
1156                 break;
1157         }
1158         switch (_computeState)
1159         {
1160         case NOT_READY:
1161                 MESSAGE(" ComputeState = NOT_READY");
1162                 break;
1163         case READY_TO_COMPUTE:
1164                 MESSAGE(" ComputeState = READY_TO_COMPUTE");
1165                 break;
1166         case COMPUTE_OK:
1167                 MESSAGE(" ComputeState = COMPUTE_OK");
1168                 break;
1169         case FAILED_TO_COMPUTE:
1170                 MESSAGE(" ComputeState = FAILED_TO_COMPUTE");
1171                 break;
1172         }
1173 }
1174
1175 //================================================================================
1176 /*!
1177  * \brief Remove nodes and elements bound to submesh
1178   * \param subMesh - submesh containing nodes and elements
1179  */
1180 //================================================================================
1181
1182 static void cleanSubMesh( SMESH_subMesh * subMesh )
1183 {
1184   if (subMesh) {
1185     if (SMESHDS_SubMesh * subMeshDS = subMesh->GetSubMeshDS()) {
1186       SMESHDS_Mesh * meshDS = subMesh->GetFather()->GetMeshDS();
1187       SMDS_ElemIteratorPtr ite = subMeshDS->GetElements();
1188       while (ite->more()) {
1189         const SMDS_MeshElement * elt = ite->next();
1190         //MESSAGE( " RM elt: "<<elt->GetID()<<" ( "<<elt->NbNodes()<<" )" );
1191         //meshDS->RemoveElement(elt);
1192         meshDS->RemoveFreeElement(elt, subMeshDS);
1193       }
1194
1195       SMDS_NodeIteratorPtr itn = subMeshDS->GetNodes();
1196       while (itn->more()) {
1197         const SMDS_MeshNode * node = itn->next();
1198         //MESSAGE( " RM node: "<<node->GetID());
1199         if ( node->NbInverseElements() == 0 )
1200           meshDS->RemoveFreeNode(node, subMeshDS);
1201         else // for StdMeshers_CompositeSegment_1D: node in one submesh, edge in another
1202           meshDS->RemoveNode(node);
1203       }
1204     }
1205   }
1206 }
1207
1208 //=============================================================================
1209 /*!
1210  *
1211  */
1212 //=============================================================================
1213
1214 bool SMESH_subMesh::ComputeStateEngine(int event)
1215 {
1216   _computeError.reset();
1217
1218   //MESSAGE("SMESH_subMesh::ComputeStateEngine");
1219   //SCRUTE(_computeState);
1220   //SCRUTE(event);
1221
1222   if (_subShape.ShapeType() == TopAbs_VERTEX)
1223   {
1224     _computeState = READY_TO_COMPUTE;
1225     SMESHDS_SubMesh* smDS = GetSubMeshDS();
1226     if ( smDS && smDS->NbNodes() ) {
1227       if ( event == CLEAN ) {
1228         CleanDependants();
1229         cleanSubMesh( this );
1230       }
1231       else
1232         _computeState = COMPUTE_OK;
1233     }
1234     else if ( event == COMPUTE && !_alwaysComputed ) {
1235       const TopoDS_Vertex & V = TopoDS::Vertex( _subShape );
1236       gp_Pnt P = BRep_Tool::Pnt(V);
1237       if ( SMDS_MeshNode * n = _father->GetMeshDS()->AddNode(P.X(), P.Y(), P.Z()) ) {
1238         _father->GetMeshDS()->SetNodeOnVertex(n,_Id);
1239         _computeState = COMPUTE_OK;
1240       }
1241     }
1242     if ( event == MODIF_ALGO_STATE )
1243       CleanDependants();
1244     return true;
1245   }
1246   SMESH_Gen *gen = _father->GetGen();
1247   SMESH_Algo *algo = 0;
1248   bool ret = true;
1249   SMESH_Hypothesis::Hypothesis_Status hyp_status;
1250   //algo_state oldAlgoState = (algo_state) GetAlgoState();
1251
1252   switch (_computeState)
1253   {
1254
1255     // ----------------------------------------------------------------------
1256
1257   case NOT_READY:
1258     switch (event)
1259     {
1260     case MODIF_ALGO_STATE:
1261       algo = gen->GetAlgo((*_father), _subShape);
1262       if (algo && !algo->NeedDescretBoundary())
1263         CleanDependsOn(); // clean sub-meshes with event CLEAN
1264       if ( _algoState == HYP_OK )
1265         _computeState = READY_TO_COMPUTE;
1266       break;
1267     case COMPUTE:               // nothing to do
1268       break;
1269     case CLEAN:
1270       CleanDependants();
1271       RemoveSubMeshElementsAndNodes();
1272       break;
1273     case SUBMESH_COMPUTED:      // nothing to do
1274       break;
1275     case SUBMESH_RESTORED:
1276       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1277       break;
1278     case MESH_ENTITY_REMOVED:
1279       break;
1280     case CHECK_COMPUTE_STATE:
1281       if ( IsMeshComputed() )
1282         _computeState = COMPUTE_OK;
1283       break;
1284     default:
1285       ASSERT(0);
1286       break;
1287     }
1288     break;
1289
1290     // ----------------------------------------------------------------------
1291
1292   case READY_TO_COMPUTE:
1293     switch (event)
1294     {
1295     case MODIF_ALGO_STATE:
1296       _computeState = NOT_READY;
1297       algo = gen->GetAlgo((*_father), _subShape);
1298       if (algo)
1299       {
1300         if (!algo->NeedDescretBoundary())
1301           CleanDependsOn(); // clean sub-meshes with event CLEAN
1302         if ( _algoState == HYP_OK )
1303           _computeState = READY_TO_COMPUTE;
1304       }
1305       break;
1306     case COMPUTE:
1307       {
1308         algo = gen->GetAlgo((*_father), _subShape);
1309         ASSERT(algo);
1310         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1311         if (!ret)
1312         {
1313           MESSAGE("***** verify compute state *****");
1314           _computeState = NOT_READY;
1315           SetAlgoState(MISSING_HYP);
1316           break;
1317         }
1318         TopoDS_Shape shape = _subShape;
1319         // check submeshes needed
1320         if (_father->HasShapeToMesh() ) {
1321           bool subComputed = false;
1322           if (!algo->OnlyUnaryInput())
1323             shape = GetCollection( gen, algo, subComputed );
1324           else
1325             subComputed = SubMeshesComputed();
1326           ret = ( algo->NeedDescretBoundary() ? subComputed :
1327                   algo->SupportSubmeshes() ? true :
1328                   ( !subComputed || _father->IsNotConformAllowed() ));
1329           if (!ret) {
1330             _computeState = FAILED_TO_COMPUTE;
1331             if ( !algo->NeedDescretBoundary() )
1332               _computeError =
1333                 SMESH_ComputeError::New(COMPERR_BAD_INPUT_MESH,
1334                                         "Unexpected computed submesh",algo);
1335             break;
1336           }
1337         }
1338         // compute
1339 //         CleanDependants(); for "UseExisting_*D" algos
1340 //         RemoveSubMeshElementsAndNodes();
1341         ret = false;
1342         _computeState = FAILED_TO_COMPUTE;
1343         _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo);
1344         try {
1345 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1346           OCC_CATCH_SIGNALS;
1347 #endif
1348           algo->InitComputeError();
1349           MemoryReserve aMemoryReserve;
1350           SMDS_Mesh::CheckMemory();
1351           if ( !_father->HasShapeToMesh() ) // no shape
1352           {
1353             SMESH_MesherHelper helper( *_father );
1354             helper.SetSubShape( shape );
1355             helper.SetElementsOnShape( true );
1356             ret = algo->Compute(*_father, &helper );
1357           }
1358           else
1359           {
1360             ret = algo->Compute((*_father), shape);
1361           }
1362           if ( !_computeError || ( !ret && _computeError->IsOK() ) ) // algo can set _computeError of submesh
1363             _computeError = algo->GetComputeError();
1364         }
1365         catch ( std::bad_alloc& exc ) {
1366           MESSAGE("std::bad_alloc thrown inside algo->Compute()");
1367           if ( _computeError ) {
1368             _computeError->myName = COMPERR_MEMORY_PB;
1369             //_computeError->myComment = exc.what();
1370           }
1371           cleanSubMesh( this );
1372           throw exc;
1373         }
1374         catch ( Standard_OutOfMemory& exc ) {
1375           MESSAGE("Standard_OutOfMemory thrown inside algo->Compute()");
1376           if ( _computeError ) {
1377             _computeError->myName = COMPERR_MEMORY_PB;
1378             //_computeError->myComment = exc.what();
1379           }
1380           cleanSubMesh( this );
1381           throw std::bad_alloc();
1382         }
1383         catch (Standard_Failure& ex) {
1384           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1385           _computeError->myName    = COMPERR_OCC_EXCEPTION;
1386           _computeError->myComment += ex.DynamicType()->Name();
1387           if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) {
1388             _computeError->myComment += ": ";
1389             _computeError->myComment += ex.GetMessageString();
1390           }
1391         }
1392         catch ( SALOME_Exception& S_ex ) {
1393           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1394           _computeError->myName    = COMPERR_SLM_EXCEPTION;
1395           _computeError->myComment = S_ex.what();
1396         }
1397         catch ( std::exception& exc ) {
1398           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1399           _computeError->myName    = COMPERR_STD_EXCEPTION;
1400           _computeError->myComment = exc.what();
1401         }
1402         catch ( ... ) {
1403           if ( _computeError )
1404             _computeError->myName = COMPERR_EXCEPTION;
1405           else
1406             ret = false;
1407         }
1408         if (ret && !_alwaysComputed && shape == _subShape) { // check if anything was built
1409           ret = ( GetSubMeshDS() && ( GetSubMeshDS()->NbElements() || GetSubMeshDS()->NbNodes() ));
1410         }
1411         bool isComputeErrorSet = !CheckComputeError( algo, shape );
1412         if (!ret && !isComputeErrorSet)
1413         {
1414           // Set _computeError
1415           if ( !_computeError )
1416             _computeError = SMESH_ComputeError::New();
1417           if ( _computeError->IsOK() )
1418             _computeError->myName = COMPERR_ALGO_FAILED;
1419           _computeState = FAILED_TO_COMPUTE;
1420         }
1421         if (ret)
1422         {
1423           _computeError.reset();
1424         }
1425         UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
1426       }
1427       break;
1428     case CLEAN:
1429       CleanDependants();
1430       RemoveSubMeshElementsAndNodes();
1431       _computeState = NOT_READY;
1432       algo = gen->GetAlgo((*_father), _subShape);
1433       if (algo)
1434       {
1435         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1436         if (ret)
1437           _computeState = READY_TO_COMPUTE;
1438         else
1439           SetAlgoState(MISSING_HYP);
1440       }
1441       break;
1442     case SUBMESH_COMPUTED:      // nothing to do
1443       break;
1444     case SUBMESH_RESTORED:
1445       // check if a mesh is already computed that may
1446       // happen after retrieval from a file
1447       ComputeStateEngine( CHECK_COMPUTE_STATE );
1448       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1449       algo = gen->GetAlgo(*_father, _subShape);
1450       if (algo) algo->SubmeshRestored( this );
1451       break;
1452     case MESH_ENTITY_REMOVED:
1453       break;
1454     case CHECK_COMPUTE_STATE:
1455       if ( IsMeshComputed() )
1456         _computeState = COMPUTE_OK;
1457       break;
1458     default:
1459       ASSERT(0);
1460       break;
1461     }
1462     break;
1463
1464     // ----------------------------------------------------------------------
1465
1466   case COMPUTE_OK:
1467     switch (event)
1468     {
1469     case MODIF_ALGO_STATE:
1470       ComputeStateEngine( CLEAN );
1471       algo = gen->GetAlgo((*_father), _subShape);
1472       if (algo && !algo->NeedDescretBoundary())
1473         CleanDependsOn(); // clean sub-meshes with event CLEAN
1474       break;
1475     case COMPUTE:               // nothing to do
1476       break;
1477     case CLEAN:
1478       CleanDependants();  // clean sub-meshes, dependant on this one, with event CLEAN
1479       RemoveSubMeshElementsAndNodes();
1480       _computeState = NOT_READY;
1481       if ( _algoState == HYP_OK )
1482         _computeState = READY_TO_COMPUTE;
1483       break;
1484     case SUBMESH_COMPUTED:      // nothing to do
1485       break;
1486     case SUBMESH_RESTORED:
1487       ComputeStateEngine( CHECK_COMPUTE_STATE );
1488       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1489       algo = gen->GetAlgo(*_father, _subShape);
1490       if (algo) algo->SubmeshRestored( this );
1491       break;
1492     case MESH_ENTITY_REMOVED:
1493       UpdateDependantsState( CHECK_COMPUTE_STATE );
1494       ComputeStateEngine( CHECK_COMPUTE_STATE );
1495       ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
1496       break;
1497     case CHECK_COMPUTE_STATE:
1498       if ( !IsMeshComputed() )
1499         if (_algoState == HYP_OK)
1500           _computeState = READY_TO_COMPUTE;
1501         else
1502           _computeState = NOT_READY;
1503       break;
1504     default:
1505       ASSERT(0);
1506       break;
1507     }
1508     break;
1509
1510     // ----------------------------------------------------------------------
1511
1512   case FAILED_TO_COMPUTE:
1513     switch (event)
1514     {
1515     case MODIF_ALGO_STATE:
1516       algo = gen->GetAlgo((*_father), _subShape);
1517       if (algo && !algo->NeedDescretBoundary())
1518         CleanDependsOn(); // clean sub-meshes with event CLEAN
1519       if (_algoState == HYP_OK)
1520         _computeState = READY_TO_COMPUTE;
1521       else
1522         _computeState = NOT_READY;
1523       break;
1524     case COMPUTE:      // nothing to do
1525       break;
1526     case CLEAN:
1527       CleanDependants(); // submeshes dependent on me should be cleaned as well
1528       RemoveSubMeshElementsAndNodes();
1529       break;
1530     case SUBMESH_COMPUTED:      // allow retry compute
1531       if (_algoState == HYP_OK)
1532         _computeState = READY_TO_COMPUTE;
1533       else
1534         _computeState = NOT_READY;
1535       break;
1536     case SUBMESH_RESTORED:
1537       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1538       break;
1539     case MESH_ENTITY_REMOVED:
1540       break;
1541     case CHECK_COMPUTE_STATE:
1542       if ( IsMeshComputed() )
1543         _computeState = COMPUTE_OK;
1544       else
1545         if (_algoState == HYP_OK)
1546           _computeState = READY_TO_COMPUTE;
1547         else
1548           _computeState = NOT_READY;
1549       break;
1550     default:
1551       ASSERT(0);
1552       break;
1553     }
1554     break;
1555
1556     // ----------------------------------------------------------------------
1557   default:
1558     ASSERT(0);
1559     break;
1560   }
1561
1562   NotifyListenersOnEvent( event, COMPUTE_EVENT );
1563
1564   return ret;
1565 }
1566
1567 //=======================================================================
1568 /*!
1569  * \brief Update compute_state by _computeError and send proper events to
1570  * dependent submeshes
1571   * \retval bool - true if _computeError is NOT set
1572  */
1573 //=======================================================================
1574
1575 bool SMESH_subMesh::CheckComputeError(SMESH_Algo* theAlgo, const TopoDS_Shape& theShape)
1576 {
1577   bool noErrors = true;
1578
1579   if ( !theShape.IsNull() )
1580   {
1581     // Check state of submeshes
1582     if ( !theAlgo->NeedDescretBoundary())
1583     {
1584       SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1585       while ( smIt->more() )
1586         if ( !smIt->next()->CheckComputeError( theAlgo ))
1587           noErrors = false;
1588     }
1589
1590     // Check state of neighbours
1591     if ( !theAlgo->OnlyUnaryInput() &&
1592          theShape.ShapeType() == TopAbs_COMPOUND &&
1593          !theShape.IsSame( _subShape ))
1594     {
1595       for (TopoDS_Iterator subIt( theShape ); subIt.More(); subIt.Next()) {
1596         SMESH_subMesh* sm = _father->GetSubMesh( subIt.Value() );
1597         if ( sm != this ) {
1598           if ( !sm->CheckComputeError( theAlgo, sm->GetSubShape() ))
1599             noErrors = false;
1600           UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
1601         }
1602       }
1603     }
1604   }
1605   {
1606     // Check my state
1607     if ( !_computeError || _computeError->IsOK() )
1608     {
1609       _computeState = COMPUTE_OK;
1610     }
1611     else
1612     {
1613       if ( !_computeError->myAlgo )
1614         _computeError->myAlgo = theAlgo;
1615
1616       // Show error
1617       SMESH_Comment text;
1618       text << theAlgo->GetName() << " failed on subshape #" << _Id << " with error ";
1619       if (_computeError->IsCommon() )
1620         text << _computeError->CommonName();
1621       else
1622         text << _computeError->myName;
1623       if ( _computeError->myComment.size() > 0 )
1624         text << " \"" << _computeError->myComment << "\"";
1625
1626 #ifdef _DEBUG_
1627       MESSAGE_BEGIN ( text );
1628       // Show vertices location of a failed shape
1629       TopTools_IndexedMapOfShape vMap;
1630       TopExp::MapShapes( _subShape, TopAbs_VERTEX, vMap );
1631       MESSAGE_ADD ( "Subshape vertices " << ( vMap.Extent()>10 ? "(first 10):" : ":") );
1632       for ( int iv = 1; iv <= vMap.Extent() && iv < 11; ++iv ) {
1633         gp_Pnt P( BRep_Tool::Pnt( TopoDS::Vertex( vMap( iv ) )));
1634         MESSAGE_ADD ( "#" << _father->GetMeshDS()->ShapeToIndex( vMap( iv )) << " "
1635                    << P.X() << " " << P.Y() << " " << P.Z() << " " );
1636       }
1637 #else
1638       INFOS( text );
1639 #endif
1640       _computeState = FAILED_TO_COMPUTE;
1641       noErrors = false;
1642     }
1643   }
1644   return noErrors;
1645 }
1646
1647 //=======================================================================
1648 //function : ApplyToCollection
1649 //purpose  : Apply theAlgo to all subshapes in theCollection
1650 //=======================================================================
1651
1652 bool SMESH_subMesh::ApplyToCollection (SMESH_Algo*         theAlgo,
1653                                        const TopoDS_Shape& theCollection)
1654 {
1655   MESSAGE("SMESH_subMesh::ApplyToCollection");
1656   ASSERT ( !theAlgo->NeedDescretBoundary() );
1657
1658   if ( _computeError )
1659     _computeError->myName = COMPERR_OK;
1660
1661   bool ok = theAlgo->Compute( *_father, theCollection );
1662
1663   // set _computeState of subshapes
1664   TopExp_Explorer anExplorer( theCollection, _subShape.ShapeType() );
1665   for ( ; anExplorer.More(); anExplorer.Next() )
1666   {
1667     if ( SMESH_subMesh* subMesh = _father->GetSubMeshContaining( anExplorer.Current() ))
1668     {
1669       bool localOK = subMesh->CheckComputeError( theAlgo );
1670       if ( !ok && localOK && !subMesh->IsMeshComputed() )
1671       {
1672         subMesh->_computeError = theAlgo->GetComputeError();
1673         if ( subMesh->_computeError->IsOK() )
1674           _computeError = SMESH_ComputeError::New(COMPERR_ALGO_FAILED);
1675         localOK = CheckComputeError( theAlgo );
1676       }
1677       if ( localOK )
1678         subMesh->UpdateDependantsState( SUBMESH_COMPUTED );
1679       subMesh->UpdateSubMeshState( localOK ? COMPUTE_OK : FAILED_TO_COMPUTE );
1680     }
1681   }
1682
1683   return true;
1684 }
1685
1686
1687 //=======================================================================
1688 //function : UpdateSubMeshState
1689 //purpose  :
1690 //=======================================================================
1691
1692 void SMESH_subMesh::UpdateSubMeshState(const compute_state theState)
1693 {
1694   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1695   while ( smIt->more() )
1696     smIt->next()->_computeState = theState;
1697 }
1698
1699 //=======================================================================
1700 //function : ComputeSubMeshStateEngine
1701 //purpose  :
1702 //=======================================================================
1703
1704 void SMESH_subMesh::ComputeSubMeshStateEngine(int event)
1705 {
1706   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1707   while ( smIt->more() )
1708     smIt->next()->ComputeStateEngine(event);
1709 }
1710
1711 //=======================================================================
1712 //function : UpdateDependantsState
1713 //purpose  :
1714 //=======================================================================
1715
1716 void SMESH_subMesh::UpdateDependantsState(const compute_event theEvent)
1717 {
1718   //MESSAGE("SMESH_subMesh::UpdateDependantsState");
1719   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1720   for (; it.More(); it.Next())
1721   {
1722     const TopoDS_Shape& ancestor = it.Value();
1723     SMESH_subMesh *aSubMesh =
1724       _father->GetSubMeshContaining(ancestor);
1725     if (aSubMesh)
1726       aSubMesh->ComputeStateEngine( theEvent );
1727   }
1728 }
1729
1730 //=============================================================================
1731 /*!
1732  *
1733  */
1734 //=============================================================================
1735
1736 void SMESH_subMesh::CleanDependants()
1737 {
1738   int dimToClean = SMESH_Gen::GetShapeDim( _subShape ) + 1;
1739
1740   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1741   for (; it.More(); it.Next())
1742   {
1743     const TopoDS_Shape& ancestor = it.Value();
1744     if ( SMESH_Gen::GetShapeDim( ancestor ) == dimToClean ) {
1745       // PAL8021. do not go upper than SOLID, else ComputeStateEngine(CLEAN)
1746       // will erase mesh on other shapes in a compound
1747       if ( ancestor.ShapeType() >= TopAbs_SOLID ) {
1748         SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor);
1749         if (aSubMesh)
1750           aSubMesh->ComputeStateEngine(CLEAN);
1751       }
1752     }
1753   }
1754 }
1755
1756 //=============================================================================
1757 /*!
1758  *
1759  */
1760 //=============================================================================
1761
1762 void SMESH_subMesh::RemoveSubMeshElementsAndNodes()
1763 {
1764   //SCRUTE(_subShape.ShapeType());
1765
1766   cleanSubMesh( this );
1767
1768   // algo may bind a submesh not to _subShape, eg 3D algo
1769   // sets nodes on SHELL while _subShape may be SOLID
1770
1771   int dim = SMESH_Gen::GetShapeDim( _subShape );
1772   int type = _subShape.ShapeType() + 1;
1773   for ( ; type <= TopAbs_EDGE; type++) {
1774     if ( dim == SMESH_Gen::GetShapeDim( (TopAbs_ShapeEnum) type ))
1775     {
1776       TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type );
1777       for ( ; exp.More(); exp.Next() )
1778         cleanSubMesh( _father->GetSubMeshContaining( exp.Current() ));
1779     }
1780     else
1781       break;
1782   }
1783 }
1784
1785 //=======================================================================
1786 //function : GetCollection
1787 //purpose  : return a shape containing all sub-shapes of the MainShape that can be
1788 //           meshed at once along with _subShape
1789 //=======================================================================
1790
1791 TopoDS_Shape SMESH_subMesh::GetCollection(SMESH_Gen * theGen,
1792                                           SMESH_Algo* theAlgo,
1793                                           bool &      theSubComputed)
1794 {
1795   MESSAGE("SMESH_subMesh::GetCollection");
1796
1797   theSubComputed = SubMeshesComputed();
1798
1799   TopoDS_Shape mainShape = _father->GetMeshDS()->ShapeToMesh();
1800
1801   if ( mainShape.IsSame( _subShape ))
1802     return _subShape;
1803
1804   const bool ignoreAuxiliaryHyps = false;
1805   list<const SMESHDS_Hypothesis*> aUsedHyp =
1806     theAlgo->GetUsedHypothesis( *_father, _subShape, ignoreAuxiliaryHyps ); // copy
1807
1808   // put in a compound all shapes with the same hypothesis assigned
1809   // and a good ComputState
1810
1811   TopoDS_Compound aCompound;
1812   BRep_Builder aBuilder;
1813   aBuilder.MakeCompound( aCompound );
1814
1815   TopExp_Explorer anExplorer( mainShape, _subShape.ShapeType() );
1816   for ( ; anExplorer.More(); anExplorer.Next() )
1817   {
1818     const TopoDS_Shape& S = anExplorer.Current();
1819     SMESH_subMesh* subMesh = _father->GetSubMesh( S );
1820     if ( subMesh == this )
1821     {
1822       aBuilder.Add( aCompound, S );
1823     }
1824     else if ( subMesh->GetComputeState() == READY_TO_COMPUTE )
1825     {
1826       SMESH_Algo* anAlgo = theGen->GetAlgo( *_father, S );
1827       if (strcmp( anAlgo->GetName(), theAlgo->GetName()) == 0 && // same algo
1828           anAlgo->GetUsedHypothesis( *_father, S, ignoreAuxiliaryHyps ) == aUsedHyp) // same hyps
1829         aBuilder.Add( aCompound, S );
1830       if ( !subMesh->SubMeshesComputed() )
1831         theSubComputed = false;
1832     }
1833   }
1834
1835   return aCompound;
1836 }
1837
1838 //=======================================================================
1839 //function : GetSimilarAttached
1840 //purpose  : return a hypothesis attached to theShape.
1841 //           If theHyp is provided, similar but not same hypotheses
1842 //           is returned; else only applicable ones having theHypType
1843 //           is returned
1844 //=======================================================================
1845
1846 const SMESH_Hypothesis* SMESH_subMesh::GetSimilarAttached(const TopoDS_Shape&      theShape,
1847                                                           const SMESH_Hypothesis * theHyp,
1848                                                           const int                theHypType)
1849 {
1850   SMESH_HypoFilter hypoKind;
1851   hypoKind.Init( hypoKind.HasType( theHyp ? theHyp->GetType() : theHypType ));
1852   if ( theHyp ) {
1853     hypoKind.And   ( hypoKind.HasDim( theHyp->GetDim() ));
1854     hypoKind.AndNot( hypoKind.Is( theHyp ));
1855     if ( theHyp->IsAuxiliary() )
1856       hypoKind.And( hypoKind.HasName( theHyp->GetName() ));
1857     else
1858       hypoKind.AndNot( hypoKind.IsAuxiliary());
1859   }
1860   else {
1861     hypoKind.And( hypoKind.IsApplicableTo( theShape ));
1862   }
1863
1864   return _father->GetHypothesis( theShape, hypoKind, false );
1865 }
1866
1867 //=======================================================================
1868 //function : CheckConcurentHypothesis
1869 //purpose  : check if there are several applicable hypothesis attached to
1870 //           ancestors
1871 //=======================================================================
1872
1873 SMESH_Hypothesis::Hypothesis_Status
1874   SMESH_subMesh::CheckConcurentHypothesis (const int theHypType)
1875 {
1876   MESSAGE ("SMESH_subMesh::CheckConcurentHypothesis");
1877
1878   // is there local hypothesis on me?
1879   if ( GetSimilarAttached( _subShape, 0, theHypType ) )
1880     return SMESH_Hypothesis::HYP_OK;
1881
1882
1883   TopoDS_Shape aPrevWithHyp;
1884   const SMESH_Hypothesis* aPrevHyp = 0;
1885   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1886   for (; it.More(); it.Next())
1887   {
1888     const TopoDS_Shape& ancestor = it.Value();
1889     const SMESH_Hypothesis* hyp = GetSimilarAttached( ancestor, 0, theHypType );
1890     if ( hyp )
1891     {
1892       if ( aPrevWithHyp.IsNull() || aPrevWithHyp.IsSame( ancestor ))
1893       {
1894         aPrevWithHyp = ancestor;
1895         aPrevHyp     = hyp;
1896       }
1897       else if ( aPrevWithHyp.ShapeType() == ancestor.ShapeType() && aPrevHyp != hyp )
1898         return SMESH_Hypothesis::HYP_CONCURENT;
1899       else
1900         return SMESH_Hypothesis::HYP_OK;
1901     }
1902   }
1903   return SMESH_Hypothesis::HYP_OK;
1904 }
1905
1906 //================================================================================
1907 /*!
1908  * \brief Sets an event listener and its data to a submesh
1909  * \param listener - the listener to store
1910  * \param data - the listener data to store
1911  * \param where - the submesh to store the listener and it's data
1912  * \param deleteListener - if true then the listener will be deleted as
1913  *        it is removed from where submesh
1914  * 
1915  * It remembers the submesh where it puts the listener in order to delete
1916  * them when HYP_OK algo_state is lost
1917  * After being set, event listener is notified on each event of where submesh.
1918  */
1919 //================================================================================
1920
1921 void SMESH_subMesh::SetEventListener(EventListener*     listener,
1922                                      EventListenerData* data,
1923                                      SMESH_subMesh*     where)
1924 {
1925   if ( listener && where ) {
1926     where->SetEventListener( listener, data );
1927     myOwnListeners.push_back( make_pair( where, listener ));
1928   }
1929 }
1930
1931 //================================================================================
1932 /*!
1933  * \brief Sets an event listener and its data to a submesh
1934  * \param listener - the listener to store
1935  * \param data - the listener data to store
1936  * 
1937  * After being set, event listener is notified on each event of a submesh.
1938  */
1939 //================================================================================
1940
1941 void SMESH_subMesh::SetEventListener(EventListener* listener, EventListenerData* data)
1942 {
1943   map< EventListener*, EventListenerData* >::iterator l_d =
1944     myEventListeners.find( listener );
1945   if ( l_d != myEventListeners.end() ) {
1946     EventListenerData* curData = l_d->second;
1947     if ( curData && curData != data && curData->IsDeletable() )
1948       delete curData;
1949     l_d->second = data;
1950   }
1951   else 
1952     myEventListeners.insert( make_pair( listener, data ));
1953 }
1954
1955 //================================================================================
1956 /*!
1957  * \brief Return an event listener data
1958  * \param listener - the listener whose data is
1959  * \retval EventListenerData* - found data, maybe NULL
1960  */
1961 //================================================================================
1962
1963 EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener) const
1964 {
1965   map< EventListener*, EventListenerData* >::const_iterator l_d =
1966     myEventListeners.find( listener );
1967   if ( l_d != myEventListeners.end() )
1968     return l_d->second;
1969   return 0;
1970 }
1971
1972 //================================================================================
1973 /*!
1974  * \brief Notify stored event listeners on the occured event
1975  * \param event - algo_event or compute_event itself
1976  * \param eventType - algo_event or compute_event
1977  * \param subMesh - the submesh where the event occures
1978  * \param data - listener data stored in the subMesh
1979  * \param hyp - hypothesis, if eventType is algo_event
1980  */
1981 //================================================================================
1982
1983 void SMESH_subMesh::NotifyListenersOnEvent( const int         event,
1984                                             const event_type  eventType,
1985                                             SMESH_Hypothesis* hyp)
1986 {
1987   map< EventListener*, EventListenerData* >::iterator l_d = myEventListeners.begin();
1988   for ( ; l_d != myEventListeners.end(); ++l_d )
1989     l_d->first->ProcessEvent( event, eventType, this, l_d->second, hyp );
1990 }
1991
1992 //================================================================================
1993 /*!
1994  * \brief Unregister the listener and delete listener's data
1995  * \param listener - the event listener
1996  */
1997 //================================================================================
1998
1999 void SMESH_subMesh::DeleteEventListener(EventListener* listener)
2000 {
2001   map< EventListener*, EventListenerData* >::iterator l_d =
2002     myEventListeners.find( listener );
2003   if ( l_d != myEventListeners.end() ) {
2004     if ( l_d->first  && l_d->first->IsDeletable() )  delete l_d->first;
2005     if ( l_d->second && l_d->second->IsDeletable() ) delete l_d->second;
2006     myEventListeners.erase( l_d );
2007   }
2008 }
2009
2010 //================================================================================
2011 /*!
2012  * \brief Delete event listeners depending on algo of this submesh
2013  */
2014 //================================================================================
2015
2016 void SMESH_subMesh::DeleteOwnListeners()
2017 {
2018   list< pair< SMESH_subMesh*, EventListener* > >::iterator sm_l;
2019   for ( sm_l = myOwnListeners.begin(); sm_l != myOwnListeners.end(); ++sm_l)
2020     sm_l->first->DeleteEventListener( sm_l->second );
2021   myOwnListeners.clear();
2022 }
2023
2024 //================================================================================
2025 /*!
2026  * \brief Do something on a certain event
2027  * \param event - algo_event or compute_event itself
2028  * \param eventType - algo_event or compute_event
2029  * \param subMesh - the submesh where the event occures
2030  * \param data - listener data stored in the subMesh
2031  * \param hyp - hypothesis, if eventType is algo_event
2032  * 
2033  * The base implementation translates CLEAN event to the subMesh
2034  * stored in listener data. Also it sends SUBMESH_COMPUTED event in case of
2035  * successful COMPUTE event.
2036  */
2037 //================================================================================
2038
2039 void SMESH_subMeshEventListener::ProcessEvent(const int          event,
2040                                               const int          eventType,
2041                                               SMESH_subMesh*     subMesh,
2042                                               EventListenerData* data,
2043                                               const SMESH_Hypothesis*  /*hyp*/)
2044 {
2045   if ( data && !data->mySubMeshes.empty() &&
2046        eventType == SMESH_subMesh::COMPUTE_EVENT)
2047   {
2048     ASSERT( data->mySubMeshes.front() != subMesh );
2049     list<SMESH_subMesh*>::iterator smIt = data->mySubMeshes.begin();
2050     list<SMESH_subMesh*>::iterator smEnd = data->mySubMeshes.end();
2051     switch ( event ) {
2052     case SMESH_subMesh::CLEAN:
2053       for ( ; smIt != smEnd; ++ smIt)
2054         (*smIt)->ComputeStateEngine( event );
2055       break;
2056     case SMESH_subMesh::COMPUTE:
2057       if ( subMesh->GetComputeState() == SMESH_subMesh::COMPUTE_OK )
2058         for ( ; smIt != smEnd; ++ smIt)
2059           (*smIt)->ComputeStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
2060       break;
2061     default:;
2062     }
2063   }
2064 }
2065
2066 namespace {
2067
2068   //================================================================================
2069   /*!
2070    * \brief Iterator over submeshes and optionally prepended or appended one
2071    */
2072   //================================================================================
2073
2074   struct _Iterator : public SMDS_Iterator<SMESH_subMesh*>
2075   {
2076     _Iterator(SMDS_Iterator<SMESH_subMesh*>* subIt,
2077               SMESH_subMesh*                 prepend,
2078               SMESH_subMesh*                 append): myIt(subIt),myAppend(append)
2079     {
2080       myCur = prepend ? prepend : myIt->more() ? myIt->next() : append;
2081       if ( myCur == append ) append = 0;
2082     }
2083     /// Return true if and only if there are other object in this iterator
2084     virtual bool more()
2085     {
2086       return myCur;
2087     }
2088     /// Return the current object and step to the next one
2089     virtual SMESH_subMesh* next()
2090     {
2091       SMESH_subMesh* res = myCur;
2092       if ( myIt->more() ) { myCur = myIt->next(); }
2093       else                { myCur = myAppend; myAppend = 0; }
2094       return res;
2095     }
2096     /// ~
2097     ~_Iterator()
2098     { delete myIt; }
2099     ///
2100     SMESH_subMesh                 *myAppend, *myCur;
2101     SMDS_Iterator<SMESH_subMesh*> *myIt;
2102   };
2103 }
2104
2105 //================================================================================
2106 /*!
2107  * \brief  Return iterator on the submeshes this one depends on
2108   * \param includeSelf - this submesh to be returned also
2109   * \param reverse - if true, complex shape submeshes go first
2110  */
2111 //================================================================================
2112
2113 SMESH_subMeshIteratorPtr SMESH_subMesh::getDependsOnIterator(const bool includeSelf,
2114                                                              const bool reverse)
2115 {
2116   SMESH_subMesh *prepend=0, *append=0;
2117   if ( includeSelf ) {
2118     if ( reverse ) prepend = this;
2119     else            append = this;
2120   }
2121   typedef map < int, SMESH_subMesh * > TMap;
2122   if ( reverse )
2123   {
2124     return SMESH_subMeshIteratorPtr
2125       ( new _Iterator( new SMDS_mapReverseIterator<TMap>( DependsOn() ), prepend, append ));
2126   }
2127   {
2128     return SMESH_subMeshIteratorPtr
2129       ( new _Iterator( new SMDS_mapIterator<TMap>( DependsOn() ), prepend, append ));
2130   }
2131 }