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