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