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