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