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