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