Salome HOME
Speed up "Clear mesh data"
[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 /*!
191  * \brief Return true if no mesh entities is bound to the submesh
192  */
193 //=======================================================================
194
195 bool SMESH_subMesh::IsEmpty() const
196 {
197   if (SMESHDS_SubMesh * subMeshDS = ((SMESH_subMesh*)this)->GetSubMeshDS())
198     return (!subMeshDS->NbElements() && !subMeshDS->NbNodes());
199   return true;
200 }
201
202 //=======================================================================
203 //function : IsMeshComputed
204 //purpose  : check if _subMeshDS contains mesh elements
205 //=======================================================================
206
207 bool SMESH_subMesh::IsMeshComputed() const
208 {
209   if ( _alwaysComputed )
210     return true;
211   // algo may bind a submesh not to _subShape, eg 3D algo
212   // sets nodes on SHELL while _subShape may be SOLID
213
214   SMESHDS_Mesh* meshDS = _father->GetMeshDS();
215   int dim = SMESH_Gen::GetShapeDim( _subShape );
216   int type = _subShape.ShapeType();
217   for ( ; type <= TopAbs_VERTEX; type++) {
218     if ( dim == SMESH_Gen::GetShapeDim( (TopAbs_ShapeEnum) type ))
219     {
220       TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type );
221       for ( ; exp.More(); exp.Next() )
222       {
223         if ( SMESHDS_SubMesh * smDS = meshDS->MeshElements( exp.Current() ))
224         {
225           bool computed = (dim > 0) ? smDS->NbElements() : smDS->NbNodes();
226           if ( computed )
227             return true;
228         }
229       }
230     }
231     else
232       break;
233   }
234
235   return false;
236 }
237
238 //=============================================================================
239 /*!
240  *
241  */
242 //=============================================================================
243
244 bool SMESH_subMesh::SubMeshesComputed()
245 {
246   int myDim = SMESH_Gen::GetShapeDim( _subShape );
247   int dimToCheck = myDim - 1;
248   bool subMeshesComputed = true;
249   // check subMeshes with upper dimension => reverse iteration
250   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,true);
251   while ( smIt->more() )
252   {
253     SMESH_subMesh *sm = smIt->next();
254     if ( sm->_alwaysComputed )
255       continue;
256     const TopoDS_Shape & ss = sm->GetSubShape();
257     // MSV 07.04.2006: restrict checking to myDim-1 only. Ex., there is no sense
258     // in checking of existence of edges if the algo needs only faces. Moreover,
259     // degenerated edges may have no submesh, as after computing NETGEN_2D.
260     int dim = SMESH_Gen::GetShapeDim( ss );
261     if (dim < dimToCheck)
262       break; // the rest subMeshes are all of less dimension
263     SMESHDS_SubMesh * ds = sm->GetSubMeshDS();
264     bool computeOk = (sm->GetComputeState() == COMPUTE_OK ||
265                       (ds && ( ds->NbNodes() || ds->NbElements() )));
266     if (!computeOk)
267     {
268       int type = ss.ShapeType();
269
270       subMeshesComputed = false;
271
272       switch (type)
273       {
274       case TopAbs_COMPOUND:
275         {
276           MESSAGE("The not computed sub mesh is a COMPOUND");
277           break;
278         }
279       case TopAbs_COMPSOLID:
280         {
281           MESSAGE("The not computed sub mesh is a COMPSOLID");
282           break;
283         }
284       case TopAbs_SHELL:
285         {
286           MESSAGE("The not computed sub mesh is a SHEL");
287           break;
288         }
289       case TopAbs_WIRE:
290         {
291           MESSAGE("The not computed sub mesh is a WIRE");
292           break;
293         }
294       case TopAbs_SOLID:
295         {
296           MESSAGE("The not computed sub mesh is a SOLID");
297           break;
298         }
299       case TopAbs_FACE:
300         {
301           MESSAGE("The not computed sub mesh is a FACE");
302           break;
303         }
304       case TopAbs_EDGE:
305         {
306           MESSAGE("The not computed sub mesh is a EDGE");
307           break;
308         }
309       default:
310         {
311           MESSAGE("The not computed sub mesh is of unknown type");
312           break;
313         }
314       }
315
316       break;
317     }
318   }
319   return subMeshesComputed;
320 }
321
322 //=============================================================================
323 /*!
324  *
325  */
326 //=============================================================================
327
328 bool SMESH_subMesh::SubMeshesReady()
329 {
330   bool subMeshesReady = true;
331   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,true);
332   while ( smIt->more() ) {
333     SMESH_subMesh *sm = smIt->next();
334     bool computeOk = (sm->GetComputeState() == COMPUTE_OK ||
335                       sm->GetComputeState() == READY_TO_COMPUTE);
336     if (!computeOk)
337     {
338       subMeshesReady = false;
339       SCRUTE(sm->GetId());
340       break;
341     }
342   }
343   return subMeshesReady;
344 }
345
346 //=============================================================================
347 /*!
348  * Construct dependence on first level subMeshes. complex shapes (compsolid,
349  * shell, wire) are not analysed the same way as simple shapes (solid, face,
350  * edge).
351  * For collection shapes (compsolid, shell, wire) prepare a list of submeshes
352  * with possible multiples occurences. Multiples occurences corresponds to
353  * internal frontiers within shapes of the collection and must not be keeped.
354  * See FinalizeDependence.
355  */
356 //=============================================================================
357
358 const map < int, SMESH_subMesh * >& SMESH_subMesh::DependsOn()
359 {
360   if (_dependenceAnalysed)
361     return _mapDepend;
362
363   //MESSAGE("SMESH_subMesh::DependsOn");
364
365   int type = _subShape.ShapeType();
366   //SCRUTE(type);
367   switch (type)
368   {
369   case TopAbs_COMPOUND:
370     {
371       //MESSAGE("compound");
372       for (TopExp_Explorer exp(_subShape, TopAbs_SOLID); exp.More();
373            exp.Next())
374       {
375         InsertDependence(exp.Current());
376       }
377       for (TopExp_Explorer exp(_subShape, TopAbs_SHELL, TopAbs_SOLID); exp.More();
378            exp.Next())
379       {
380           InsertDependence(exp.Current());      //only shell not in solid
381       }
382       for (TopExp_Explorer exp(_subShape, TopAbs_FACE, TopAbs_SHELL); exp.More();
383            exp.Next())
384       {
385         InsertDependence(exp.Current());
386       }
387       for (TopExp_Explorer exp(_subShape, TopAbs_EDGE, TopAbs_FACE); exp.More();
388            exp.Next())
389       {
390         InsertDependence(exp.Current());
391       }
392       break;
393     }
394   case TopAbs_COMPSOLID:
395     {
396                 //MESSAGE("compsolid");
397       for (TopExp_Explorer exp(_subShape, TopAbs_SOLID); exp.More();
398            exp.Next())
399       {
400         InsertDependence(exp.Current());
401       }
402       break;
403     }
404   case TopAbs_SHELL:
405     {
406       //MESSAGE("shell");
407       for (TopExp_Explorer exp(_subShape, TopAbs_FACE); exp.More();
408            exp.Next())
409       {
410         InsertDependence(exp.Current());
411       }
412       break;
413     }
414   case TopAbs_WIRE:
415     {
416       //MESSAGE("wire");
417       for (TopExp_Explorer exp(_subShape, TopAbs_EDGE); exp.More();
418            exp.Next())
419       {
420         InsertDependence(exp.Current());
421       }
422       break;
423     }
424   case TopAbs_SOLID:
425     {
426       //MESSAGE("solid");
427       if(_father->HasShapeToMesh()) {
428         for (TopExp_Explorer exp(_subShape, TopAbs_FACE); exp.More();
429              exp.Next())
430         {
431           InsertDependence(exp.Current());
432         }
433       }
434       break;
435     }
436   case TopAbs_FACE:
437     {
438       //MESSAGE("face");
439       for (TopExp_Explorer exp(_subShape, TopAbs_EDGE); exp.More();
440            exp.Next())
441       {
442         InsertDependence(exp.Current());
443       }
444       break;
445     }
446   case TopAbs_EDGE:
447     {
448       //MESSAGE("edge");
449       for (TopExp_Explorer exp(_subShape, TopAbs_VERTEX); exp.More();
450            exp.Next())
451       {
452                         InsertDependence(exp.Current());
453                       }
454       break;
455     }
456   case TopAbs_VERTEX:
457     {
458       break;
459     }
460   default:
461     {
462       break;
463     }
464   }
465   _dependenceAnalysed = true;
466   return _mapDepend;
467 }
468
469 //=============================================================================
470 /*!
471  * For simple Shapes (solid, face, edge): add subMesh into dependence list.
472  */
473 //=============================================================================
474
475 void SMESH_subMesh::InsertDependence(const TopoDS_Shape aSubShape)
476 {
477   //MESSAGE("SMESH_subMesh::InsertDependence");
478   SMESH_subMesh *aSubMesh = _father->GetSubMesh(aSubShape);
479   int type = aSubShape.ShapeType();
480   int ordType = 9 - type;               // 2 = Vertex, 8 = CompSolid
481   int cle = aSubMesh->GetId();
482   cle += 10000000 * ordType;    // sort map by ordType then index
483   if ( _mapDepend.find( cle ) == _mapDepend.end())
484   {
485     _mapDepend[cle] = aSubMesh;
486     const map < int, SMESH_subMesh * > & subMap = aSubMesh->DependsOn();
487     _mapDepend.insert( subMap.begin(), subMap.end() );
488   }
489 }
490
491 //=============================================================================
492 /*!
493  *
494  */
495 //=============================================================================
496
497 const TopoDS_Shape & SMESH_subMesh::GetSubShape() const
498 {
499         //MESSAGE("SMESH_subMesh::GetSubShape");
500         return _subShape;
501 }
502
503
504 //=======================================================================
505 //function : CanAddHypothesis
506 //purpose  : return true if theHypothesis can be attached to me:
507 //           its dimention is checked
508 //=======================================================================
509
510 bool SMESH_subMesh::CanAddHypothesis(const SMESH_Hypothesis* theHypothesis) const
511 {
512   int aHypDim   = theHypothesis->GetDim();
513   int aShapeDim = SMESH_Gen::GetShapeDim(_subShape);
514   if (aHypDim == 3 && aShapeDim == 3) {
515     // check case of open shell
516     //if (_subShape.ShapeType() == TopAbs_SHELL && !_subShape.Closed())
517     if (_subShape.ShapeType() == TopAbs_SHELL && !BRep_Tool::IsClosed(_subShape))
518       return false;
519   }
520   if ( aHypDim <= aShapeDim )
521     return true;
522
523   return false;
524 }
525
526 //=======================================================================
527 //function : IsApplicableHypotesis
528 //purpose  :
529 //=======================================================================
530
531 bool SMESH_subMesh::IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis,
532                                           const TopAbs_ShapeEnum  theShapeType)
533 {
534   if ( theHypothesis->GetType() > SMESHDS_Hypothesis::PARAM_ALGO)
535     // algorithm
536     return ( theHypothesis->GetShapeType() & (1<< theShapeType));
537
538   // hypothesis
539   switch ( theShapeType ) {
540   case TopAbs_VERTEX:
541   case TopAbs_EDGE:
542   case TopAbs_FACE:
543   case TopAbs_SOLID:
544     return SMESH_Gen::GetShapeDim( theShapeType ) == theHypothesis->GetDim();
545
546   case TopAbs_SHELL:
547     // Special case for algorithms, building 2D mesh on a whole shell.
548     // Before this fix there was a problem after restoring from study,
549     // because in that case algorithm is assigned before hypothesis
550     // (on shell in problem case) and hypothesis is checked on faces
551     // (because it is 2D), where we have NO_ALGO state.
552     // Now 2D hypothesis is also applicable to shells.
553     return (theHypothesis->GetDim() == 2 || theHypothesis->GetDim() == 3);
554
555 //   case TopAbs_WIRE:
556 //   case TopAbs_COMPSOLID:
557 //   case TopAbs_COMPOUND:
558   default:;
559   }
560   return false;
561 }
562
563 //=============================================================================
564 /*!
565  *
566  */
567 //=============================================================================
568
569 SMESH_Hypothesis::Hypothesis_Status
570   SMESH_subMesh::AlgoStateEngine(int event, SMESH_Hypothesis * anHyp)
571 {
572   //  MESSAGE("SMESH_subMesh::AlgoStateEngine");
573   //SCRUTE(_algoState);
574   //SCRUTE(event);
575
576   // **** les retour des evenement shape sont significatifs
577   // (add ou remove fait ou non)
578   // le retour des evenement father n'indiquent pas que add ou remove fait
579
580   SMESH_Hypothesis::Hypothesis_Status aux_ret, ret = SMESH_Hypothesis::HYP_OK;
581
582   SMESHDS_Mesh* meshDS =_father->GetMeshDS();
583   SMESH_Gen*    gen    =_father->GetGen();
584   SMESH_Algo*   algo   = 0;
585
586   if (_subShape.ShapeType() == TopAbs_VERTEX )
587   {
588     if ( anHyp->GetDim() != 0) {
589       if (event == ADD_HYP || event == ADD_ALGO)
590         return SMESH_Hypothesis::HYP_BAD_DIM;
591       else
592         return SMESH_Hypothesis::HYP_OK;
593     }
594     // 0D hypothesis
595     else if ( _algoState == HYP_OK ) {
596       // update default _algoState
597       if ( event != REMOVE_FATHER_ALGO )
598       {
599         _algoState = NO_ALGO;
600         algo = gen->GetAlgo(*_father, _subShape);
601         if ( algo ) {
602           _algoState = MISSING_HYP;
603           if ( event == REMOVE_FATHER_HYP ||
604                algo->CheckHypothesis(*_father,_subShape, aux_ret))
605             _algoState = HYP_OK;
606         }
607       }
608     }
609   }
610
611   int oldAlgoState = _algoState;
612   bool modifiedHyp = (event == MODIF_HYP);  // if set to true, force event MODIF_ALGO_STATE
613
614   bool isApplicableHyp = IsApplicableHypotesis( anHyp );
615
616   if (event == ADD_ALGO || event == ADD_FATHER_ALGO)
617   {
618     // -------------------------------------------
619     // check if a shape needed by algo is present
620     // -------------------------------------------
621     algo = static_cast< SMESH_Algo* >( anHyp );
622     if ( !_father->HasShapeToMesh() && algo->NeedShape() )
623       return SMESH_Hypothesis::HYP_NEED_SHAPE;
624     // ----------------------
625     // check mesh conformity
626     // ----------------------
627     if (isApplicableHyp && !_father->IsNotConformAllowed() && !IsConform( algo ))
628       return SMESH_Hypothesis::HYP_NOTCONFORM;
629   }
630
631   // ----------------------------------
632   // add a hypothesis to DS if possible
633   // ----------------------------------
634   if (event == ADD_HYP || event == ADD_ALGO)
635   {
636     if ( ! CanAddHypothesis( anHyp )) // check dimension
637       return SMESH_Hypothesis::HYP_BAD_DIM;
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() && !upperAlgo->SupportSubmeshes())
986           ret = SMESH_Hypothesis::HYP_HIDDEN_ALGO;
987     }
988     // is algo hiding?
989     if ( ret == SMESH_Hypothesis::HYP_OK &&
990          !algo->NeedDescretBoundary()    &&
991          !algo->SupportSubmeshes()) {
992       map<int, SMESH_subMesh*>::reverse_iterator i_sm = _mapDepend.rbegin();
993       for ( ; ( ret == SMESH_Hypothesis::HYP_OK && i_sm != _mapDepend.rend()) ; ++i_sm )
994         if ( gen->GetAlgo( *_father, i_sm->second->_subShape ))
995           ret = SMESH_Hypothesis::HYP_HIDING_ALGO;
996     }
997   }
998
999   bool stateChange = ( _algoState != oldAlgoState );
1000
1001   if ( stateChange && _algoState == HYP_OK ) // hyp becomes OK
1002     algo->SetEventListener( this );
1003
1004   NotifyListenersOnEvent( event, ALGO_EVENT, anHyp );
1005
1006   if ( stateChange && oldAlgoState == HYP_OK ) { // hyp becomes KO
1007     DeleteOwnListeners();
1008     SetIsAlwaysComputed( false );
1009     if (_subShape.ShapeType() == TopAbs_VERTEX ) {
1010       // restore default states
1011       _algoState = HYP_OK;
1012       _computeState = READY_TO_COMPUTE;
1013     }
1014   }
1015
1016   if (stateChange || modifiedHyp)
1017     ComputeStateEngine(MODIF_ALGO_STATE);
1018
1019   return ret;
1020 }
1021
1022 //=======================================================================
1023 //function : IsConform
1024 //purpose  : check if a conform mesh will be produced by the Algo
1025 //=======================================================================
1026
1027 bool SMESH_subMesh::IsConform(const SMESH_Algo* theAlgo)
1028 {
1029 //  MESSAGE( "SMESH_subMesh::IsConform" );
1030   if ( !theAlgo ) return false;
1031
1032   // Suppose that theAlgo is applicable to _subShape, do not check it here
1033   //if ( !IsApplicableHypotesis( theAlgo )) return false;
1034
1035   // check only algo that doesn't NeedDescretBoundary(): because mesh made
1036   // on a sub-shape will be ignored by theAlgo
1037   if ( theAlgo->NeedDescretBoundary() ||
1038        !theAlgo->OnlyUnaryInput() ) // all adjacent shapes will be meshed by this algo?
1039     return true;
1040
1041   SMESH_Gen* gen =_father->GetGen();
1042
1043   // only local algo is to be checked
1044   //if ( gen->IsGlobalHypothesis( theAlgo, *_father ))
1045   if ( _subShape.ShapeType() == _father->GetMeshDS()->ShapeToMesh().ShapeType() )
1046     return true;
1047
1048   // check algo attached to adjacent shapes
1049
1050   // loop on one level down sub-meshes
1051   TopoDS_Iterator itsub( _subShape );
1052   for (; itsub.More(); itsub.Next())
1053   {
1054     // loop on adjacent subShapes
1055     TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( itsub.Value() ));
1056     for (; it.More(); it.Next())
1057     {
1058       const TopoDS_Shape& adjacent = it.Value();
1059       if ( _subShape.IsSame( adjacent )) continue;
1060       if ( adjacent.ShapeType() != _subShape.ShapeType())
1061         break;
1062
1063       // check algo attached to smAdjacent
1064       SMESH_Algo * algo = gen->GetAlgo((*_father), adjacent);
1065       if (algo &&
1066           !algo->NeedDescretBoundary() &&
1067           algo->OnlyUnaryInput())
1068         return false; // NOT CONFORM MESH WILL BE PRODUCED
1069     }
1070   }
1071
1072   return true;
1073 }
1074
1075 //=============================================================================
1076 /*!
1077  *
1078  */
1079 //=============================================================================
1080
1081 void SMESH_subMesh::SetAlgoState(int state)
1082 {
1083   _algoState = state;
1084 }
1085
1086 //=============================================================================
1087 /*!
1088  *
1089  */
1090 //=============================================================================
1091 SMESH_Hypothesis::Hypothesis_Status
1092   SMESH_subMesh::SubMeshesAlgoStateEngine(int event,
1093                                           SMESH_Hypothesis * anHyp)
1094 {
1095   SMESH_Hypothesis::Hypothesis_Status ret = SMESH_Hypothesis::HYP_OK;
1096   //EAP: a wire (dim==1) should notify edges (dim==1)
1097   //EAP: int dim = SMESH_Gen::GetShapeDim(_subShape);
1098   //if (_subShape.ShapeType() < TopAbs_EDGE ) // wire,face etc
1099   {
1100     SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1101     while ( smIt->more() ) {
1102       SMESH_Hypothesis::Hypothesis_Status ret2 =
1103         smIt->next()->AlgoStateEngine(event, anHyp);
1104       if ( ret2 > ret )
1105         ret = ret2;
1106     }
1107   }
1108   return ret;
1109 }
1110
1111 //=============================================================================
1112 /*!
1113  *
1114  */
1115 //=============================================================================
1116
1117 void SMESH_subMesh::CleanDependsOn()
1118 {
1119   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1120   while ( smIt->more() )
1121     smIt->next()->ComputeStateEngine(CLEAN);
1122 }
1123
1124 //=============================================================================
1125 /*!
1126  *
1127  */
1128 //=============================================================================
1129
1130 void SMESH_subMesh::DumpAlgoState(bool isMain)
1131 {
1132         int dim = SMESH_Gen::GetShapeDim(_subShape);
1133 //   if (dim < 1) return;
1134         if (isMain)
1135         {
1136                 const map < int, SMESH_subMesh * >&subMeshes = DependsOn();
1137
1138                 map < int, SMESH_subMesh * >::const_iterator itsub;
1139                 for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++)
1140                 {
1141                         SMESH_subMesh *sm = (*itsub).second;
1142                         sm->DumpAlgoState(false);
1143                 }
1144         }
1145         int type = _subShape.ShapeType();
1146         MESSAGE("dim = " << dim << " type of shape " << type);
1147         switch (_algoState)
1148         {
1149         case NO_ALGO:
1150                 MESSAGE(" AlgoState = NO_ALGO");
1151                 break;
1152         case MISSING_HYP:
1153                 MESSAGE(" AlgoState = MISSING_HYP");
1154                 break;
1155         case HYP_OK:
1156                 MESSAGE(" AlgoState = HYP_OK");
1157                 break;
1158         }
1159         switch (_computeState)
1160         {
1161         case NOT_READY:
1162                 MESSAGE(" ComputeState = NOT_READY");
1163                 break;
1164         case READY_TO_COMPUTE:
1165                 MESSAGE(" ComputeState = READY_TO_COMPUTE");
1166                 break;
1167         case COMPUTE_OK:
1168                 MESSAGE(" ComputeState = COMPUTE_OK");
1169                 break;
1170         case FAILED_TO_COMPUTE:
1171                 MESSAGE(" ComputeState = FAILED_TO_COMPUTE");
1172                 break;
1173         }
1174 }
1175
1176 //================================================================================
1177 /*!
1178  * \brief Remove nodes and elements bound to submesh
1179   * \param subMesh - submesh containing nodes and elements
1180  */
1181 //================================================================================
1182
1183 static void cleanSubMesh( SMESH_subMesh * subMesh )
1184 {
1185   if (subMesh) {
1186     if (SMESHDS_SubMesh * subMeshDS = subMesh->GetSubMeshDS()) {
1187       SMESHDS_Mesh * meshDS = subMesh->GetFather()->GetMeshDS();
1188       SMDS_ElemIteratorPtr ite = subMeshDS->GetElements();
1189       while (ite->more()) {
1190         const SMDS_MeshElement * elt = ite->next();
1191         //MESSAGE( " RM elt: "<<elt->GetID()<<" ( "<<elt->NbNodes()<<" )" );
1192         //meshDS->RemoveElement(elt);
1193         meshDS->RemoveFreeElement(elt, subMeshDS);
1194       }
1195
1196       SMDS_NodeIteratorPtr itn = subMeshDS->GetNodes();
1197       while (itn->more()) {
1198         const SMDS_MeshNode * node = itn->next();
1199         //MESSAGE( " RM node: "<<node->GetID());
1200         if ( node->NbInverseElements() == 0 )
1201           meshDS->RemoveFreeNode(node, subMeshDS);
1202         else // for StdMeshers_CompositeSegment_1D: node in one submesh, edge in another
1203           meshDS->RemoveNode(node);
1204       }
1205     }
1206   }
1207 }
1208
1209 //=============================================================================
1210 /*!
1211  *
1212  */
1213 //=============================================================================
1214
1215 bool SMESH_subMesh::ComputeStateEngine(int event)
1216 {
1217   _computeError.reset();
1218
1219   //MESSAGE("SMESH_subMesh::ComputeStateEngine");
1220   //SCRUTE(_computeState);
1221   //SCRUTE(event);
1222
1223   if (_subShape.ShapeType() == TopAbs_VERTEX)
1224   {
1225     _computeState = READY_TO_COMPUTE;
1226     SMESHDS_SubMesh* smDS = GetSubMeshDS();
1227     if ( smDS && smDS->NbNodes() ) {
1228       if ( event == CLEAN ) {
1229         CleanDependants();
1230         cleanSubMesh( this );
1231       }
1232       else
1233         _computeState = COMPUTE_OK;
1234     }
1235     else if ( event == COMPUTE && !_alwaysComputed ) {
1236       const TopoDS_Vertex & V = TopoDS::Vertex( _subShape );
1237       gp_Pnt P = BRep_Tool::Pnt(V);
1238       if ( SMDS_MeshNode * n = _father->GetMeshDS()->AddNode(P.X(), P.Y(), P.Z()) ) {
1239         _father->GetMeshDS()->SetNodeOnVertex(n,_Id);
1240         _computeState = COMPUTE_OK;
1241       }
1242     }
1243     if ( event == MODIF_ALGO_STATE )
1244       CleanDependants();
1245     return true;
1246   }
1247   SMESH_Gen *gen = _father->GetGen();
1248   SMESH_Algo *algo = 0;
1249   bool ret = true;
1250   SMESH_Hypothesis::Hypothesis_Status hyp_status;
1251   //algo_state oldAlgoState = (algo_state) GetAlgoState();
1252
1253   switch (_computeState)
1254   {
1255
1256     // ----------------------------------------------------------------------
1257
1258   case NOT_READY:
1259     switch (event)
1260     {
1261     case MODIF_ALGO_STATE:
1262       algo = gen->GetAlgo((*_father), _subShape);
1263       if (algo && !algo->NeedDescretBoundary())
1264         CleanDependsOn(); // clean sub-meshes with event CLEAN
1265       if ( _algoState == HYP_OK )
1266         _computeState = READY_TO_COMPUTE;
1267       break;
1268     case COMPUTE:               // nothing to do
1269       break;
1270     case CLEAN:
1271       CleanDependants();
1272       RemoveSubMeshElementsAndNodes();
1273       break;
1274     case SUBMESH_COMPUTED:      // nothing to do
1275       break;
1276     case SUBMESH_RESTORED:
1277       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1278       break;
1279     case MESH_ENTITY_REMOVED:
1280       break;
1281     case CHECK_COMPUTE_STATE:
1282       if ( IsMeshComputed() )
1283         _computeState = COMPUTE_OK;
1284       break;
1285     default:
1286       ASSERT(0);
1287       break;
1288     }
1289     break;
1290
1291     // ----------------------------------------------------------------------
1292
1293   case READY_TO_COMPUTE:
1294     switch (event)
1295     {
1296     case MODIF_ALGO_STATE:
1297       _computeState = NOT_READY;
1298       algo = gen->GetAlgo((*_father), _subShape);
1299       if (algo)
1300       {
1301         if (!algo->NeedDescretBoundary())
1302           CleanDependsOn(); // clean sub-meshes with event CLEAN
1303         if ( _algoState == HYP_OK )
1304           _computeState = READY_TO_COMPUTE;
1305       }
1306       break;
1307     case COMPUTE:
1308       {
1309         algo = gen->GetAlgo((*_father), _subShape);
1310         ASSERT(algo);
1311         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1312         if (!ret)
1313         {
1314           MESSAGE("***** verify compute state *****");
1315           _computeState = NOT_READY;
1316           SetAlgoState(MISSING_HYP);
1317           break;
1318         }
1319         TopoDS_Shape shape = _subShape;
1320         // check submeshes needed
1321         if (_father->HasShapeToMesh() ) {
1322           bool subComputed = false;
1323           if (!algo->OnlyUnaryInput())
1324             shape = GetCollection( gen, algo, subComputed );
1325           else
1326             subComputed = SubMeshesComputed();
1327           ret = ( algo->NeedDescretBoundary() ? subComputed :
1328                   algo->SupportSubmeshes() ? true :
1329                   ( !subComputed || _father->IsNotConformAllowed() ));
1330           if (!ret) {
1331             _computeState = FAILED_TO_COMPUTE;
1332             if ( !algo->NeedDescretBoundary() )
1333               _computeError =
1334                 SMESH_ComputeError::New(COMPERR_BAD_INPUT_MESH,
1335                                         "Unexpected computed submesh",algo);
1336             break;
1337           }
1338         }
1339         // compute
1340 //         CleanDependants(); for "UseExisting_*D" algos
1341 //         RemoveSubMeshElementsAndNodes();
1342         ret = false;
1343         _computeState = FAILED_TO_COMPUTE;
1344         _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo);
1345         try {
1346 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1347           OCC_CATCH_SIGNALS;
1348 #endif
1349           algo->InitComputeError();
1350           MemoryReserve aMemoryReserve;
1351           SMDS_Mesh::CheckMemory();
1352           if ( !_father->HasShapeToMesh() ) // no shape
1353           {
1354             SMESH_MesherHelper helper( *_father );
1355             helper.SetSubShape( shape );
1356             helper.SetElementsOnShape( true );
1357             ret = algo->Compute(*_father, &helper );
1358           }
1359           else
1360           {
1361             ret = algo->Compute((*_father), shape);
1362           }
1363           if ( !ret && _computeError->IsOK() ) // algo can set _computeError of submesh
1364             _computeError = algo->GetComputeError();
1365         }
1366         catch ( std::bad_alloc& exc ) {
1367           MESSAGE("std::bad_alloc thrown inside algo->Compute()");
1368           if ( _computeError ) {
1369             _computeError->myName = COMPERR_MEMORY_PB;
1370             //_computeError->myComment = exc.what();
1371           }
1372           cleanSubMesh( this );
1373           throw exc;
1374         }
1375         catch ( Standard_OutOfMemory& exc ) {
1376           MESSAGE("Standard_OutOfMemory thrown inside algo->Compute()");
1377           if ( _computeError ) {
1378             _computeError->myName = COMPERR_MEMORY_PB;
1379             //_computeError->myComment = exc.what();
1380           }
1381           cleanSubMesh( this );
1382           throw std::bad_alloc();
1383         }
1384         catch (Standard_Failure& ex) {
1385           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1386           _computeError->myName    = COMPERR_OCC_EXCEPTION;
1387           _computeError->myComment += ex.DynamicType()->Name();
1388           if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) {
1389             _computeError->myComment += ": ";
1390             _computeError->myComment += ex.GetMessageString();
1391           }
1392         }
1393         catch ( SALOME_Exception& S_ex ) {
1394           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1395           _computeError->myName    = COMPERR_SLM_EXCEPTION;
1396           _computeError->myComment = S_ex.what();
1397         }
1398         catch ( std::exception& exc ) {
1399           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1400           _computeError->myName    = COMPERR_STD_EXCEPTION;
1401           _computeError->myComment = exc.what();
1402         }
1403         catch ( ... ) {
1404           if ( _computeError )
1405             _computeError->myName = COMPERR_EXCEPTION;
1406           else
1407             ret = false;
1408         }
1409         if (ret && !_alwaysComputed && shape == _subShape) { // check if anything was built
1410           ret = ( GetSubMeshDS() && ( GetSubMeshDS()->NbElements() || GetSubMeshDS()->NbNodes() ));
1411         }
1412         bool isComputeErrorSet = !CheckComputeError( algo, shape );
1413         if (!ret && !isComputeErrorSet)
1414         {
1415           // Set _computeError
1416           if ( !_computeError )
1417             _computeError = SMESH_ComputeError::New();
1418           if ( _computeError->IsOK() )
1419             _computeError->myName = COMPERR_ALGO_FAILED;
1420           _computeState = FAILED_TO_COMPUTE;
1421         }
1422         if (ret)
1423         {
1424           _computeError.reset();
1425         }
1426         UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
1427       }
1428       break;
1429     case CLEAN:
1430       CleanDependants();
1431       RemoveSubMeshElementsAndNodes();
1432       _computeState = NOT_READY;
1433       algo = gen->GetAlgo((*_father), _subShape);
1434       if (algo)
1435       {
1436         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1437         if (ret)
1438           _computeState = READY_TO_COMPUTE;
1439         else
1440           SetAlgoState(MISSING_HYP);
1441       }
1442       break;
1443     case SUBMESH_COMPUTED:      // nothing to do
1444       break;
1445     case SUBMESH_RESTORED:
1446       // check if a mesh is already computed that may
1447       // happen after retrieval from a file
1448       ComputeStateEngine( CHECK_COMPUTE_STATE );
1449       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1450       algo = gen->GetAlgo(*_father, _subShape);
1451       if (algo) algo->SubmeshRestored( this );
1452       break;
1453     case MESH_ENTITY_REMOVED:
1454       break;
1455     case CHECK_COMPUTE_STATE:
1456       if ( IsMeshComputed() )
1457         _computeState = COMPUTE_OK;
1458       break;
1459     default:
1460       ASSERT(0);
1461       break;
1462     }
1463     break;
1464
1465     // ----------------------------------------------------------------------
1466
1467   case COMPUTE_OK:
1468     switch (event)
1469     {
1470     case MODIF_ALGO_STATE:
1471       ComputeStateEngine( CLEAN );
1472       algo = gen->GetAlgo((*_father), _subShape);
1473       if (algo && !algo->NeedDescretBoundary())
1474         CleanDependsOn(); // clean sub-meshes with event CLEAN
1475       break;
1476     case COMPUTE:               // nothing to do
1477       break;
1478     case CLEAN:
1479       CleanDependants();  // clean sub-meshes, dependant on this one, with event CLEAN
1480       RemoveSubMeshElementsAndNodes();
1481       _computeState = NOT_READY;
1482       if ( _algoState == HYP_OK )
1483         _computeState = READY_TO_COMPUTE;
1484       break;
1485     case SUBMESH_COMPUTED:      // nothing to do
1486       break;
1487     case SUBMESH_RESTORED:
1488       ComputeStateEngine( CHECK_COMPUTE_STATE );
1489       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1490       algo = gen->GetAlgo(*_father, _subShape);
1491       if (algo) algo->SubmeshRestored( this );
1492       break;
1493     case MESH_ENTITY_REMOVED:
1494       UpdateDependantsState( CHECK_COMPUTE_STATE );
1495       ComputeStateEngine( CHECK_COMPUTE_STATE );
1496       ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
1497       break;
1498     case CHECK_COMPUTE_STATE:
1499       if ( !IsMeshComputed() )
1500         if (_algoState == HYP_OK)
1501           _computeState = READY_TO_COMPUTE;
1502         else
1503           _computeState = NOT_READY;
1504       break;
1505     default:
1506       ASSERT(0);
1507       break;
1508     }
1509     break;
1510
1511     // ----------------------------------------------------------------------
1512
1513   case FAILED_TO_COMPUTE:
1514     switch (event)
1515     {
1516     case MODIF_ALGO_STATE:
1517       algo = gen->GetAlgo((*_father), _subShape);
1518       if (algo && !algo->NeedDescretBoundary())
1519         CleanDependsOn(); // clean sub-meshes with event CLEAN
1520       if (_algoState == HYP_OK)
1521         _computeState = READY_TO_COMPUTE;
1522       else
1523         _computeState = NOT_READY;
1524       break;
1525     case COMPUTE:      // nothing to do
1526       break;
1527     case CLEAN:
1528       CleanDependants(); // submeshes dependent on me should be cleaned as well
1529       RemoveSubMeshElementsAndNodes();
1530       break;
1531     case SUBMESH_COMPUTED:      // allow retry compute
1532       if (_algoState == HYP_OK)
1533         _computeState = READY_TO_COMPUTE;
1534       else
1535         _computeState = NOT_READY;
1536       break;
1537     case SUBMESH_RESTORED:
1538       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1539       break;
1540     case MESH_ENTITY_REMOVED:
1541       break;
1542     case CHECK_COMPUTE_STATE:
1543       if ( IsMeshComputed() )
1544         _computeState = COMPUTE_OK;
1545       else
1546         if (_algoState == HYP_OK)
1547           _computeState = READY_TO_COMPUTE;
1548         else
1549           _computeState = NOT_READY;
1550       break;
1551     default:
1552       ASSERT(0);
1553       break;
1554     }
1555     break;
1556
1557     // ----------------------------------------------------------------------
1558   default:
1559     ASSERT(0);
1560     break;
1561   }
1562
1563   NotifyListenersOnEvent( event, COMPUTE_EVENT );
1564
1565   return ret;
1566 }
1567
1568 //=======================================================================
1569 /*!
1570  * \brief Update compute_state by _computeError and send proper events to
1571  * dependent submeshes
1572   * \retval bool - true if _computeError is NOT set
1573  */
1574 //=======================================================================
1575
1576 bool SMESH_subMesh::CheckComputeError(SMESH_Algo* theAlgo, const TopoDS_Shape& theShape)
1577 {
1578   bool noErrors = true;
1579
1580   if ( !theShape.IsNull() )
1581   {
1582     // Check state of submeshes
1583     if ( !theAlgo->NeedDescretBoundary())
1584     {
1585       SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1586       while ( smIt->more() )
1587         if ( !smIt->next()->CheckComputeError( theAlgo ))
1588           noErrors = false;
1589     }
1590
1591     // Check state of neighbours
1592     if ( !theAlgo->OnlyUnaryInput() &&
1593          theShape.ShapeType() == TopAbs_COMPOUND &&
1594          !theShape.IsSame( _subShape ))
1595     {
1596       for (TopoDS_Iterator subIt( theShape ); subIt.More(); subIt.Next()) {
1597         SMESH_subMesh* sm = _father->GetSubMesh( subIt.Value() );
1598         if ( sm != this ) {
1599           if ( !sm->CheckComputeError( theAlgo, sm->GetSubShape() ))
1600             noErrors = false;
1601           UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
1602         }
1603       }
1604     }
1605   }
1606   {
1607     // Check my state
1608     if ( !_computeError || _computeError->IsOK() )
1609     {
1610       _computeState = COMPUTE_OK;
1611     }
1612     else
1613     {
1614       if ( !_computeError->myAlgo )
1615         _computeError->myAlgo = theAlgo;
1616
1617       // Show error
1618       SMESH_Comment text;
1619       text << theAlgo->GetName() << " failed on subshape #" << _Id << " with error ";
1620       if (_computeError->IsCommon() )
1621         text << _computeError->CommonName();
1622       else
1623         text << _computeError->myName;
1624       if ( _computeError->myComment.size() > 0 )
1625         text << " \"" << _computeError->myComment << "\"";
1626
1627 #ifdef _DEBUG_
1628       MESSAGE_BEGIN ( text );
1629       // Show vertices location of a failed shape
1630       TopTools_IndexedMapOfShape vMap;
1631       TopExp::MapShapes( _subShape, TopAbs_VERTEX, vMap );
1632       MESSAGE_ADD ( "Subshape vertices " << ( vMap.Extent()>10 ? "(first 10):" : ":") );
1633       for ( int iv = 1; iv <= vMap.Extent() && iv < 11; ++iv ) {
1634         gp_Pnt P( BRep_Tool::Pnt( TopoDS::Vertex( vMap( iv ) )));
1635         MESSAGE_ADD ( "#" << _father->GetMeshDS()->ShapeToIndex( vMap( iv )) << " "
1636                    << P.X() << " " << P.Y() << " " << P.Z() << " " );
1637       }
1638 #else
1639       INFOS( text );
1640 #endif
1641       _computeState = FAILED_TO_COMPUTE;
1642       noErrors = false;
1643     }
1644   }
1645   return noErrors;
1646 }
1647
1648 //=======================================================================
1649 //function : ApplyToCollection
1650 //purpose  : Apply theAlgo to all subshapes in theCollection
1651 //=======================================================================
1652
1653 bool SMESH_subMesh::ApplyToCollection (SMESH_Algo*         theAlgo,
1654                                        const TopoDS_Shape& theCollection)
1655 {
1656   MESSAGE("SMESH_subMesh::ApplyToCollection");
1657   ASSERT ( !theAlgo->NeedDescretBoundary() );
1658
1659   if ( _computeError )
1660     _computeError->myName = COMPERR_OK;
1661
1662   bool ok = theAlgo->Compute( *_father, theCollection );
1663
1664   // set _computeState of subshapes
1665   TopExp_Explorer anExplorer( theCollection, _subShape.ShapeType() );
1666   for ( ; anExplorer.More(); anExplorer.Next() )
1667   {
1668     if ( SMESH_subMesh* subMesh = _father->GetSubMeshContaining( anExplorer.Current() ))
1669     {
1670       bool localOK = subMesh->CheckComputeError( theAlgo );
1671       if ( !ok && localOK && !subMesh->IsMeshComputed() )
1672       {
1673         subMesh->_computeError = theAlgo->GetComputeError();
1674         if ( subMesh->_computeError->IsOK() )
1675           _computeError = SMESH_ComputeError::New(COMPERR_ALGO_FAILED);
1676         localOK = CheckComputeError( theAlgo );
1677       }
1678       if ( localOK )
1679         subMesh->UpdateDependantsState( SUBMESH_COMPUTED );
1680       subMesh->UpdateSubMeshState( localOK ? COMPUTE_OK : FAILED_TO_COMPUTE );
1681     }
1682   }
1683
1684   return true;
1685 }
1686
1687
1688 //=======================================================================
1689 //function : UpdateSubMeshState
1690 //purpose  :
1691 //=======================================================================
1692
1693 void SMESH_subMesh::UpdateSubMeshState(const compute_state theState)
1694 {
1695   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1696   while ( smIt->more() )
1697     smIt->next()->_computeState = theState;
1698 }
1699
1700 //=======================================================================
1701 //function : ComputeSubMeshStateEngine
1702 //purpose  :
1703 //=======================================================================
1704
1705 void SMESH_subMesh::ComputeSubMeshStateEngine(int event)
1706 {
1707   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1708   while ( smIt->more() )
1709     smIt->next()->ComputeStateEngine(event);
1710 }
1711
1712 //=======================================================================
1713 //function : UpdateDependantsState
1714 //purpose  :
1715 //=======================================================================
1716
1717 void SMESH_subMesh::UpdateDependantsState(const compute_event theEvent)
1718 {
1719   //MESSAGE("SMESH_subMesh::UpdateDependantsState");
1720   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1721   for (; it.More(); it.Next())
1722   {
1723     const TopoDS_Shape& ancestor = it.Value();
1724     SMESH_subMesh *aSubMesh =
1725       _father->GetSubMeshContaining(ancestor);
1726     if (aSubMesh)
1727       aSubMesh->ComputeStateEngine( theEvent );
1728   }
1729 }
1730
1731 //=============================================================================
1732 /*!
1733  *
1734  */
1735 //=============================================================================
1736
1737 void SMESH_subMesh::CleanDependants()
1738 {
1739   int dimToClean = SMESH_Gen::GetShapeDim( _subShape ) + 1;
1740
1741   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1742   for (; it.More(); it.Next())
1743   {
1744     const TopoDS_Shape& ancestor = it.Value();
1745     if ( SMESH_Gen::GetShapeDim( ancestor ) == dimToClean ) {
1746       // PAL8021. do not go upper than SOLID, else ComputeStateEngine(CLEAN)
1747       // will erase mesh on other shapes in a compound
1748       if ( ancestor.ShapeType() >= TopAbs_SOLID ) {
1749         SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor);
1750         if (aSubMesh)
1751           aSubMesh->ComputeStateEngine(CLEAN);
1752       }
1753     }
1754   }
1755 }
1756
1757 //=============================================================================
1758 /*!
1759  *
1760  */
1761 //=============================================================================
1762
1763 void SMESH_subMesh::RemoveSubMeshElementsAndNodes()
1764 {
1765   //SCRUTE(_subShape.ShapeType());
1766
1767   cleanSubMesh( this );
1768
1769   // algo may bind a submesh not to _subShape, eg 3D algo
1770   // sets nodes on SHELL while _subShape may be SOLID
1771
1772   int dim = SMESH_Gen::GetShapeDim( _subShape );
1773   int type = _subShape.ShapeType() + 1;
1774   for ( ; type <= TopAbs_EDGE; type++) {
1775     if ( dim == SMESH_Gen::GetShapeDim( (TopAbs_ShapeEnum) type ))
1776     {
1777       TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type );
1778       for ( ; exp.More(); exp.Next() )
1779         cleanSubMesh( _father->GetSubMeshContaining( exp.Current() ));
1780     }
1781     else
1782       break;
1783   }
1784 }
1785
1786 //=======================================================================
1787 //function : GetCollection
1788 //purpose  : return a shape containing all sub-shapes of the MainShape that can be
1789 //           meshed at once along with _subShape
1790 //=======================================================================
1791
1792 TopoDS_Shape SMESH_subMesh::GetCollection(SMESH_Gen * theGen,
1793                                           SMESH_Algo* theAlgo,
1794                                           bool &      theSubComputed)
1795 {
1796   MESSAGE("SMESH_subMesh::GetCollection");
1797
1798   theSubComputed = SubMeshesComputed();
1799
1800   TopoDS_Shape mainShape = _father->GetMeshDS()->ShapeToMesh();
1801
1802   if ( mainShape.IsSame( _subShape ))
1803     return _subShape;
1804
1805   const bool ignoreAuxiliaryHyps = false;
1806   list<const SMESHDS_Hypothesis*> aUsedHyp =
1807     theAlgo->GetUsedHypothesis( *_father, _subShape, ignoreAuxiliaryHyps ); // copy
1808
1809   // put in a compound all shapes with the same hypothesis assigned
1810   // and a good ComputState
1811
1812   TopoDS_Compound aCompound;
1813   BRep_Builder aBuilder;
1814   aBuilder.MakeCompound( aCompound );
1815
1816   TopExp_Explorer anExplorer( mainShape, _subShape.ShapeType() );
1817   for ( ; anExplorer.More(); anExplorer.Next() )
1818   {
1819     const TopoDS_Shape& S = anExplorer.Current();
1820     SMESH_subMesh* subMesh = _father->GetSubMesh( S );
1821     if ( subMesh == this )
1822     {
1823       aBuilder.Add( aCompound, S );
1824     }
1825     else if ( subMesh->GetComputeState() == READY_TO_COMPUTE )
1826     {
1827       SMESH_Algo* anAlgo = theGen->GetAlgo( *_father, S );
1828       if (strcmp( anAlgo->GetName(), theAlgo->GetName()) == 0 && // same algo
1829           anAlgo->GetUsedHypothesis( *_father, S, ignoreAuxiliaryHyps ) == aUsedHyp) // same hyps
1830         aBuilder.Add( aCompound, S );
1831       if ( !subMesh->SubMeshesComputed() )
1832         theSubComputed = false;
1833     }
1834   }
1835
1836   return aCompound;
1837 }
1838
1839 //=======================================================================
1840 //function : GetSimilarAttached
1841 //purpose  : return a hypothesis attached to theShape.
1842 //           If theHyp is provided, similar but not same hypotheses
1843 //           is returned; else only applicable ones having theHypType
1844 //           is returned
1845 //=======================================================================
1846
1847 const SMESH_Hypothesis* SMESH_subMesh::GetSimilarAttached(const TopoDS_Shape&      theShape,
1848                                                           const SMESH_Hypothesis * theHyp,
1849                                                           const int                theHypType)
1850 {
1851   SMESH_HypoFilter hypoKind;
1852   hypoKind.Init( hypoKind.HasType( theHyp ? theHyp->GetType() : theHypType ));
1853   if ( theHyp ) {
1854     hypoKind.And   ( hypoKind.HasDim( theHyp->GetDim() ));
1855     hypoKind.AndNot( hypoKind.Is( theHyp ));
1856     if ( theHyp->IsAuxiliary() )
1857       hypoKind.And( hypoKind.HasName( theHyp->GetName() ));
1858     else
1859       hypoKind.AndNot( hypoKind.IsAuxiliary());
1860   }
1861   else {
1862     hypoKind.And( hypoKind.IsApplicableTo( theShape ));
1863   }
1864
1865   return _father->GetHypothesis( theShape, hypoKind, false );
1866 }
1867
1868 //=======================================================================
1869 //function : CheckConcurentHypothesis
1870 //purpose  : check if there are several applicable hypothesis attached to
1871 //           ancestors
1872 //=======================================================================
1873
1874 SMESH_Hypothesis::Hypothesis_Status
1875   SMESH_subMesh::CheckConcurentHypothesis (const int theHypType)
1876 {
1877   MESSAGE ("SMESH_subMesh::CheckConcurentHypothesis");
1878
1879   // is there local hypothesis on me?
1880   if ( GetSimilarAttached( _subShape, 0, theHypType ) )
1881     return SMESH_Hypothesis::HYP_OK;
1882
1883
1884   TopoDS_Shape aPrevWithHyp;
1885   const SMESH_Hypothesis* aPrevHyp = 0;
1886   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1887   for (; it.More(); it.Next())
1888   {
1889     const TopoDS_Shape& ancestor = it.Value();
1890     const SMESH_Hypothesis* hyp = GetSimilarAttached( ancestor, 0, theHypType );
1891     if ( hyp )
1892     {
1893       if ( aPrevWithHyp.IsNull() || aPrevWithHyp.IsSame( ancestor ))
1894       {
1895         aPrevWithHyp = ancestor;
1896         aPrevHyp     = hyp;
1897       }
1898       else if ( aPrevWithHyp.ShapeType() == ancestor.ShapeType() && aPrevHyp != hyp )
1899         return SMESH_Hypothesis::HYP_CONCURENT;
1900       else
1901         return SMESH_Hypothesis::HYP_OK;
1902     }
1903   }
1904   return SMESH_Hypothesis::HYP_OK;
1905 }
1906
1907 //================================================================================
1908 /*!
1909  * \brief Sets an event listener and its data to a submesh
1910  * \param listener - the listener to store
1911  * \param data - the listener data to store
1912  * \param where - the submesh to store the listener and it's data
1913  * \param deleteListener - if true then the listener will be deleted as
1914  *        it is removed from where submesh
1915  * 
1916  * It remembers the submesh where it puts the listener in order to delete
1917  * them when HYP_OK algo_state is lost
1918  * After being set, event listener is notified on each event of where submesh.
1919  */
1920 //================================================================================
1921
1922 void SMESH_subMesh::SetEventListener(EventListener*     listener,
1923                                      EventListenerData* data,
1924                                      SMESH_subMesh*     where)
1925 {
1926   if ( listener && where ) {
1927     where->SetEventListener( listener, data );
1928     myOwnListeners.push_back( make_pair( where, listener ));
1929   }
1930 }
1931
1932 //================================================================================
1933 /*!
1934  * \brief Sets an event listener and its data to a submesh
1935  * \param listener - the listener to store
1936  * \param data - the listener data to store
1937  * 
1938  * After being set, event listener is notified on each event of a submesh.
1939  */
1940 //================================================================================
1941
1942 void SMESH_subMesh::SetEventListener(EventListener* listener, EventListenerData* data)
1943 {
1944   map< EventListener*, EventListenerData* >::iterator l_d =
1945     myEventListeners.find( listener );
1946   if ( l_d != myEventListeners.end() ) {
1947     EventListenerData* curData = l_d->second;
1948     if ( curData && curData != data && curData->IsDeletable() )
1949       delete curData;
1950     l_d->second = data;
1951   }
1952   else 
1953     myEventListeners.insert( make_pair( listener, data ));
1954 }
1955
1956 //================================================================================
1957 /*!
1958  * \brief Return an event listener data
1959  * \param listener - the listener whose data is
1960  * \retval EventListenerData* - found data, maybe NULL
1961  */
1962 //================================================================================
1963
1964 EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener) const
1965 {
1966   map< EventListener*, EventListenerData* >::const_iterator l_d =
1967     myEventListeners.find( listener );
1968   if ( l_d != myEventListeners.end() )
1969     return l_d->second;
1970   return 0;
1971 }
1972
1973 //================================================================================
1974 /*!
1975  * \brief Notify stored event listeners on the occured event
1976  * \param event - algo_event or compute_event itself
1977  * \param eventType - algo_event or compute_event
1978  * \param subMesh - the submesh where the event occures
1979  * \param data - listener data stored in the subMesh
1980  * \param hyp - hypothesis, if eventType is algo_event
1981  */
1982 //================================================================================
1983
1984 void SMESH_subMesh::NotifyListenersOnEvent( const int         event,
1985                                             const event_type  eventType,
1986                                             SMESH_Hypothesis* hyp)
1987 {
1988   map< EventListener*, EventListenerData* >::iterator l_d = myEventListeners.begin();
1989   for ( ; l_d != myEventListeners.end(); ++l_d )
1990     l_d->first->ProcessEvent( event, eventType, this, l_d->second, hyp );
1991 }
1992
1993 //================================================================================
1994 /*!
1995  * \brief Unregister the listener and delete listener's data
1996  * \param listener - the event listener
1997  */
1998 //================================================================================
1999
2000 void SMESH_subMesh::DeleteEventListener(EventListener* listener)
2001 {
2002   map< EventListener*, EventListenerData* >::iterator l_d =
2003     myEventListeners.find( listener );
2004   if ( l_d != myEventListeners.end() ) {
2005     if ( l_d->first  && l_d->first->IsDeletable() )  delete l_d->first;
2006     if ( l_d->second && l_d->second->IsDeletable() ) delete l_d->second;
2007     myEventListeners.erase( l_d );
2008   }
2009 }
2010
2011 //================================================================================
2012 /*!
2013  * \brief Delete event listeners depending on algo of this submesh
2014  */
2015 //================================================================================
2016
2017 void SMESH_subMesh::DeleteOwnListeners()
2018 {
2019   list< pair< SMESH_subMesh*, EventListener* > >::iterator sm_l;
2020   for ( sm_l = myOwnListeners.begin(); sm_l != myOwnListeners.end(); ++sm_l)
2021     sm_l->first->DeleteEventListener( sm_l->second );
2022   myOwnListeners.clear();
2023 }
2024
2025 //================================================================================
2026 /*!
2027  * \brief Do something on a certain event
2028  * \param event - algo_event or compute_event itself
2029  * \param eventType - algo_event or compute_event
2030  * \param subMesh - the submesh where the event occures
2031  * \param data - listener data stored in the subMesh
2032  * \param hyp - hypothesis, if eventType is algo_event
2033  * 
2034  * The base implementation translates CLEAN event to the subMesh
2035  * stored in listener data. Also it sends SUBMESH_COMPUTED event in case of
2036  * successful COMPUTE event.
2037  */
2038 //================================================================================
2039
2040 void SMESH_subMeshEventListener::ProcessEvent(const int          event,
2041                                               const int          eventType,
2042                                               SMESH_subMesh*     subMesh,
2043                                               EventListenerData* data,
2044                                               const SMESH_Hypothesis*  /*hyp*/)
2045 {
2046   if ( data && !data->mySubMeshes.empty() &&
2047        eventType == SMESH_subMesh::COMPUTE_EVENT)
2048   {
2049     ASSERT( data->mySubMeshes.front() != subMesh );
2050     list<SMESH_subMesh*>::iterator smIt = data->mySubMeshes.begin();
2051     list<SMESH_subMesh*>::iterator smEnd = data->mySubMeshes.end();
2052     switch ( event ) {
2053     case SMESH_subMesh::CLEAN:
2054       for ( ; smIt != smEnd; ++ smIt)
2055         (*smIt)->ComputeStateEngine( event );
2056       break;
2057     case SMESH_subMesh::COMPUTE:
2058       if ( subMesh->GetComputeState() == SMESH_subMesh::COMPUTE_OK )
2059         for ( ; smIt != smEnd; ++ smIt)
2060           (*smIt)->ComputeStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
2061       break;
2062     default:;
2063     }
2064   }
2065 }
2066
2067 namespace {
2068
2069   //================================================================================
2070   /*!
2071    * \brief Iterator over submeshes and optionally prepended or appended one
2072    */
2073   //================================================================================
2074
2075   struct _Iterator : public SMDS_Iterator<SMESH_subMesh*>
2076   {
2077     _Iterator(SMDS_Iterator<SMESH_subMesh*>* subIt,
2078               SMESH_subMesh*                 prepend,
2079               SMESH_subMesh*                 append): myIt(subIt),myAppend(append)
2080     {
2081       myCur = prepend ? prepend : myIt->more() ? myIt->next() : append;
2082       if ( myCur == append ) append = 0;
2083     }
2084     /// Return true if and only if there are other object in this iterator
2085     virtual bool more()
2086     {
2087       return myCur;
2088     }
2089     /// Return the current object and step to the next one
2090     virtual SMESH_subMesh* next()
2091     {
2092       SMESH_subMesh* res = myCur;
2093       if ( myIt->more() ) { myCur = myIt->next(); }
2094       else                { myCur = myAppend; myAppend = 0; }
2095       return res;
2096     }
2097     /// ~
2098     ~_Iterator()
2099     { delete myIt; }
2100     ///
2101     SMESH_subMesh                 *myAppend, *myCur;
2102     SMDS_Iterator<SMESH_subMesh*> *myIt;
2103   };
2104 }
2105
2106 //================================================================================
2107 /*!
2108  * \brief  Return iterator on the submeshes this one depends on
2109   * \param includeSelf - this submesh to be returned also
2110   * \param reverse - if true, complex shape submeshes go first
2111  */
2112 //================================================================================
2113
2114 SMESH_subMeshIteratorPtr SMESH_subMesh::getDependsOnIterator(const bool includeSelf,
2115                                                              const bool reverse)
2116 {
2117   SMESH_subMesh *prepend=0, *append=0;
2118   if ( includeSelf ) {
2119     if ( reverse ) prepend = this;
2120     else            append = this;
2121   }
2122   typedef map < int, SMESH_subMesh * > TMap;
2123   if ( reverse )
2124   {
2125     return SMESH_subMeshIteratorPtr
2126       ( new _Iterator( new SMDS_mapReverseIterator<TMap>( DependsOn() ), prepend, append ));
2127   }
2128   {
2129     return SMESH_subMeshIteratorPtr
2130       ( new _Iterator( new SMDS_mapIterator<TMap>( DependsOn() ), prepend, append ));
2131   }
2132 }