Salome HOME
Merge from V6_main (04/10/2012)
[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         // check if an error reported on any sub-shape
1470         bool isComputeErrorSet = !checkComputeError( algo, ret, shape );
1471         // check if anything was built
1472         TopExp_Explorer subS(shape, _subShape.ShapeType());
1473         if (ret)
1474         {
1475           for (; ret && subS.More(); subS.Next())
1476             ret = _father->GetSubMesh( subS.Current() )->IsMeshComputed();
1477         }
1478         // Set _computeError
1479         if (!ret && !isComputeErrorSet)
1480         {
1481           for (subS.ReInit(); subS.More(); subS.Next())
1482           {
1483             SMESH_subMesh* sm = _father->GetSubMesh( subS.Current() );
1484             if ( !sm->IsMeshComputed() )
1485             {
1486               if ( !sm->_computeError )
1487                 sm->_computeError = SMESH_ComputeError::New();
1488               if ( sm->_computeError->IsOK() )
1489                 sm->_computeError->myName = COMPERR_ALGO_FAILED;
1490               sm->_computeState = FAILED_TO_COMPUTE;
1491               sm->_computeError->myAlgo = algo;
1492             }
1493           }
1494         }
1495         if (ret && _computeError && _computeError->myName != COMPERR_WARNING )
1496         {
1497           _computeError.reset();
1498         }
1499         updateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
1500       }
1501       break;
1502 #ifdef WITH_SMESH_CANCEL_COMPUTE
1503     case COMPUTE_CANCELED:               // nothing to do
1504       break;
1505 #endif
1506     case CLEAN:
1507       cleanDependants();
1508       removeSubMeshElementsAndNodes();
1509       _computeState = NOT_READY;
1510       algo = GetAlgo();
1511       if (algo)
1512       {
1513         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1514         if (ret)
1515           _computeState = READY_TO_COMPUTE;
1516         else
1517           setAlgoState(MISSING_HYP);
1518       }
1519       break;
1520     case SUBMESH_COMPUTED:      // nothing to do
1521       break;
1522     case SUBMESH_RESTORED:
1523       // check if a mesh is already computed that may
1524       // happen after retrieval from a file
1525       ComputeStateEngine( CHECK_COMPUTE_STATE );
1526       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1527       algo = GetAlgo();
1528       if (algo) algo->SubmeshRestored( this );
1529       break;
1530     case MESH_ENTITY_REMOVED:
1531       break;
1532     case SUBMESH_LOADED:
1533       loadDependentMeshes();
1534       ComputeSubMeshStateEngine( SUBMESH_LOADED );
1535       //break;
1536     case CHECK_COMPUTE_STATE:
1537       if ( IsMeshComputed() )
1538         _computeState = COMPUTE_OK;
1539       break;
1540     default:
1541       ASSERT(0);
1542       break;
1543     }
1544     break;
1545
1546     // ----------------------------------------------------------------------
1547
1548   case COMPUTE_OK:
1549     switch (event)
1550     {
1551     case MODIF_ALGO_STATE:
1552       ComputeStateEngine( CLEAN );
1553       algo = GetAlgo();
1554       if (algo && !algo->NeedDiscreteBoundary())
1555         cleanDependsOn(); // clean sub-meshes with event CLEAN
1556       break;
1557     case COMPUTE:               // nothing to do
1558       break;
1559 #ifdef WITH_SMESH_CANCEL_COMPUTE
1560     case COMPUTE_CANCELED:               // nothing to do
1561       break;
1562 #endif
1563     case CLEAN:
1564       cleanDependants();  // clean sub-meshes, dependant on this one, with event CLEAN
1565       removeSubMeshElementsAndNodes();
1566       _computeState = NOT_READY;
1567       if ( _algoState == HYP_OK )
1568         _computeState = READY_TO_COMPUTE;
1569       break;
1570     case SUBMESH_COMPUTED:      // nothing to do
1571       break;
1572     case SUBMESH_RESTORED:
1573       ComputeStateEngine( CHECK_COMPUTE_STATE );
1574       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1575       algo = GetAlgo();
1576       if (algo) algo->SubmeshRestored( this );
1577       break;
1578     case MESH_ENTITY_REMOVED:
1579       updateDependantsState    ( CHECK_COMPUTE_STATE );
1580       ComputeStateEngine       ( CHECK_COMPUTE_STATE );
1581       ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
1582       break;
1583     case CHECK_COMPUTE_STATE:
1584       if ( !IsMeshComputed() ) {
1585         if (_algoState == HYP_OK)
1586           _computeState = READY_TO_COMPUTE;
1587         else
1588           _computeState = NOT_READY;
1589       }
1590       break;
1591     case SUBMESH_LOADED:
1592       // already treated event, thanks to which _computeState == COMPUTE_OK
1593       break;
1594     default:
1595       ASSERT(0);
1596       break;
1597     }
1598     break;
1599
1600     // ----------------------------------------------------------------------
1601
1602   case FAILED_TO_COMPUTE:
1603     switch (event)
1604     {
1605     case MODIF_ALGO_STATE:
1606       if ( !IsEmpty() )
1607         ComputeStateEngine( CLEAN );
1608       algo = GetAlgo();
1609       if (algo && !algo->NeedDiscreteBoundary())
1610         cleanDependsOn(); // clean sub-meshes with event CLEAN
1611       if (_algoState == HYP_OK)
1612         _computeState = READY_TO_COMPUTE;
1613       else
1614         _computeState = NOT_READY;
1615       break;
1616     case COMPUTE:      // nothing to do
1617       break;
1618     case COMPUTE_CANCELED:
1619       {
1620         algo = GetAlgo();
1621         algo->CancelCompute();
1622       }
1623       break;
1624     case CLEAN:
1625       cleanDependants(); // submeshes dependent on me should be cleaned as well
1626       removeSubMeshElementsAndNodes();
1627       break;
1628     case SUBMESH_COMPUTED:      // allow retry compute
1629       if (_algoState == HYP_OK)
1630         _computeState = READY_TO_COMPUTE;
1631       else
1632         _computeState = NOT_READY;
1633       break;
1634     case SUBMESH_RESTORED:
1635       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1636       break;
1637     case MESH_ENTITY_REMOVED:
1638       break;
1639     case CHECK_COMPUTE_STATE:
1640       if ( IsMeshComputed() )
1641         _computeState = COMPUTE_OK;
1642       else
1643         if (_algoState == HYP_OK)
1644           _computeState = READY_TO_COMPUTE;
1645         else
1646           _computeState = NOT_READY;
1647       break;
1648     // case SUBMESH_LOADED:
1649     //   break;
1650     default:
1651       ASSERT(0);
1652       break;
1653     }
1654     break;
1655
1656     // ----------------------------------------------------------------------
1657   default:
1658     ASSERT(0);
1659     break;
1660   }
1661
1662   notifyListenersOnEvent( event, COMPUTE_EVENT );
1663
1664   return ret;
1665 }
1666
1667
1668 //=============================================================================
1669 /*!
1670  *
1671  */
1672 //=============================================================================
1673
1674 bool SMESH_subMesh::Evaluate(MapShapeNbElems& aResMap)
1675 {
1676   _computeError.reset();
1677
1678   bool ret = true;
1679
1680   if (_subShape.ShapeType() == TopAbs_VERTEX) {
1681     vector<int> aVec(SMDSEntity_Last,0);
1682     aVec[SMDSEntity_Node] = 1;
1683     aResMap.insert(make_pair(this,aVec));
1684     return ret;
1685   }
1686
1687   //SMESH_Gen *gen = _father->GetGen();
1688   SMESH_Algo *algo = 0;
1689   SMESH_Hypothesis::Hypothesis_Status hyp_status;
1690
1691   algo = GetAlgo();
1692   if(algo && !aResMap.count(this) )
1693   {
1694     ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1695     if (!ret) return false;
1696
1697     if (_father->HasShapeToMesh() && algo->NeedDiscreteBoundary())
1698     {
1699       // check submeshes needed
1700       bool subMeshEvaluated = true;
1701       int dimToCheck = SMESH_Gen::GetShapeDim( _subShape ) - 1;
1702       SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,/*complexShapeFirst=*/true);
1703       while ( smIt->more() && subMeshEvaluated )
1704       {
1705         SMESH_subMesh* sm = smIt->next();
1706         int dim = SMESH_Gen::GetShapeDim( sm->GetSubShape() );
1707         if (dim < dimToCheck) break; // the rest subMeshes are all of less dimension
1708         const vector<int> & nbs = aResMap[ sm ];
1709         subMeshEvaluated = (std::accumulate( nbs.begin(), nbs.end(), 0 ) > 0 );
1710       }
1711       if ( !subMeshEvaluated )
1712         return false;
1713     }
1714     _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo);
1715     ret = algo->Evaluate((*_father), _subShape, aResMap);
1716
1717     aResMap.insert( make_pair( this,vector<int>(0)));
1718   }
1719
1720   return ret;
1721 }
1722
1723
1724 //=======================================================================
1725 /*!
1726  * \brief Update compute_state by _computeError and send proper events to
1727  * dependent submeshes
1728   * \retval bool - true if _computeError is NOT set
1729  */
1730 //=======================================================================
1731
1732 bool SMESH_subMesh::checkComputeError(SMESH_Algo*         theAlgo,
1733                                       const bool          theComputeOK,
1734                                       const TopoDS_Shape& theShape)
1735 {
1736   bool noErrors = true;
1737
1738   if ( !theShape.IsNull() )
1739   {
1740     // Check state of submeshes
1741     if ( !theAlgo->NeedDiscreteBoundary())
1742     {
1743       SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1744       while ( smIt->more() )
1745         if ( !smIt->next()->checkComputeError( theAlgo, theComputeOK ))
1746           noErrors = false;
1747     }
1748
1749     // Check state of neighbours
1750     if ( !theAlgo->OnlyUnaryInput() &&
1751          theShape.ShapeType() == TopAbs_COMPOUND &&
1752          !theShape.IsSame( _subShape ))
1753     {
1754       for (TopoDS_Iterator subIt( theShape ); subIt.More(); subIt.Next()) {
1755         SMESH_subMesh* sm = _father->GetSubMesh( subIt.Value() );
1756         if ( sm != this ) {
1757           if ( !sm->checkComputeError( theAlgo, theComputeOK, sm->GetSubShape() ))
1758             noErrors = false;
1759           updateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
1760         }
1761       }
1762     }
1763   }
1764   {
1765
1766     // Set my _computeState
1767
1768     if ( !_computeError || _computeError->IsOK() )
1769     {
1770       // no error description is set to this sub-mesh, check if any mesh is computed
1771       _computeState = IsMeshComputed() ? COMPUTE_OK : FAILED_TO_COMPUTE;
1772       if ( _computeState != COMPUTE_OK )
1773       {
1774         if ( _subShape.ShapeType() == TopAbs_EDGE &&
1775              BRep_Tool::Degenerated( TopoDS::Edge( _subShape )) )
1776           _computeState = COMPUTE_OK;
1777         else if ( theComputeOK )
1778           _computeError = SMESH_ComputeError::New(COMPERR_NO_MESH_ON_SHAPE,"",theAlgo);
1779       }
1780     }
1781
1782     if ( _computeError && !_computeError->IsOK() )
1783     {
1784       if ( !_computeError->myAlgo )
1785         _computeError->myAlgo = theAlgo;
1786
1787       // Show error
1788       SMESH_Comment text;
1789       text << theAlgo->GetName() << " failed on sub-shape #" << _Id << " with error ";
1790       if (_computeError->IsCommon() )
1791         text << _computeError->CommonName();
1792       else
1793         text << _computeError->myName;
1794       if ( _computeError->myComment.size() > 0 )
1795         text << " \"" << _computeError->myComment << "\"";
1796
1797       INFOS( text );
1798
1799       _computeState = _computeError->IsKO() ? FAILED_TO_COMPUTE : COMPUTE_OK;
1800
1801       noErrors = false;
1802     }
1803   }
1804   return noErrors;
1805 }
1806
1807 //=======================================================================
1808 //function : updateSubMeshState
1809 //purpose  :
1810 //=======================================================================
1811
1812 void SMESH_subMesh::updateSubMeshState(const compute_state theState)
1813 {
1814   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1815   while ( smIt->more() )
1816     smIt->next()->_computeState = theState;
1817 }
1818
1819 //=======================================================================
1820 //function : ComputeSubMeshStateEngine
1821 //purpose  :
1822 //=======================================================================
1823
1824 void SMESH_subMesh::ComputeSubMeshStateEngine(int event, const bool includeSelf)
1825 {
1826   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(includeSelf,false);
1827   while ( smIt->more() )
1828     smIt->next()->ComputeStateEngine(event);
1829 }
1830
1831 //=======================================================================
1832 //function : updateDependantsState
1833 //purpose  :
1834 //=======================================================================
1835
1836 void SMESH_subMesh::updateDependantsState(const compute_event theEvent)
1837 {
1838   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1839   for (; it.More(); it.Next())
1840   {
1841     const TopoDS_Shape& ancestor = it.Value();
1842     SMESH_subMesh *aSubMesh =
1843       _father->GetSubMeshContaining(ancestor);
1844     if (aSubMesh)
1845       aSubMesh->ComputeStateEngine( theEvent );
1846   }
1847 }
1848
1849 //=============================================================================
1850 /*!
1851  *
1852  */
1853 //=============================================================================
1854
1855 void SMESH_subMesh::cleanDependants()
1856 {
1857   int dimToClean = SMESH_Gen::GetShapeDim( _subShape ) + 1;
1858
1859   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1860   for (; it.More(); it.Next())
1861   {
1862     const TopoDS_Shape& ancestor = it.Value();
1863     if ( SMESH_Gen::GetShapeDim( ancestor ) == dimToClean ) {
1864       // PAL8021. do not go upper than SOLID, else ComputeStateEngine(CLEAN)
1865       // will erase mesh on other shapes in a compound
1866       if ( ancestor.ShapeType() >= TopAbs_SOLID ) {
1867         SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor);
1868         if (aSubMesh &&
1869             !aSubMesh->IsEmpty() ) // prevent infinite CLEAN via event lesteners
1870           aSubMesh->ComputeStateEngine(CLEAN);
1871       }
1872     }
1873   }
1874 }
1875
1876 //=============================================================================
1877 /*!
1878  *
1879  */
1880 //=============================================================================
1881
1882 void SMESH_subMesh::removeSubMeshElementsAndNodes()
1883 {
1884   cleanSubMesh( this );
1885
1886   // algo may bind a submesh not to _subShape, eg 3D algo
1887   // sets nodes on SHELL while _subShape may be SOLID
1888
1889   int dim = SMESH_Gen::GetShapeDim( _subShape );
1890   int type = _subShape.ShapeType() + 1;
1891   for ( ; type <= TopAbs_EDGE; type++) {
1892     if ( dim == SMESH_Gen::GetShapeDim( (TopAbs_ShapeEnum) type ))
1893     {
1894       TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type );
1895       for ( ; exp.More(); exp.Next() )
1896         cleanSubMesh( _father->GetSubMeshContaining( exp.Current() ));
1897     }
1898     else
1899       break;
1900   }
1901 }
1902
1903 //=======================================================================
1904 //function : getCollection
1905 //purpose  : return a shape containing all sub-shapes of the MainShape that can be
1906 //           meshed at once along with _subShape
1907 //=======================================================================
1908
1909 TopoDS_Shape SMESH_subMesh::getCollection(SMESH_Gen * theGen,
1910                                           SMESH_Algo* theAlgo,
1911                                           bool &      theSubComputed)
1912 {
1913   theSubComputed = subMeshesComputed();
1914
1915   TopoDS_Shape mainShape = _father->GetMeshDS()->ShapeToMesh();
1916
1917   if ( mainShape.IsSame( _subShape ))
1918     return _subShape;
1919
1920   const bool ignoreAuxiliaryHyps = false;
1921   list<const SMESHDS_Hypothesis*> aUsedHyp =
1922     theAlgo->GetUsedHypothesis( *_father, _subShape, ignoreAuxiliaryHyps ); // copy
1923
1924   // put in a compound all shapes with the same hypothesis assigned
1925   // and a good ComputState
1926
1927   TopoDS_Compound aCompound;
1928   BRep_Builder aBuilder;
1929   aBuilder.MakeCompound( aCompound );
1930
1931   TopExp_Explorer anExplorer( mainShape, _subShape.ShapeType() );
1932   for ( ; anExplorer.More(); anExplorer.Next() )
1933   {
1934     const TopoDS_Shape& S = anExplorer.Current();
1935     SMESH_subMesh* subMesh = _father->GetSubMesh( S );
1936     if ( subMesh == this )
1937     {
1938       aBuilder.Add( aCompound, S );
1939     }
1940     else if ( subMesh->GetComputeState() == READY_TO_COMPUTE )
1941     {
1942       SMESH_Algo* anAlgo = theGen->GetAlgo( *_father, S );
1943       if (strcmp( anAlgo->GetName(), theAlgo->GetName()) == 0 && // same algo
1944           anAlgo->GetUsedHypothesis( *_father, S, ignoreAuxiliaryHyps ) == aUsedHyp) // same hyps
1945         aBuilder.Add( aCompound, S );
1946       if ( !subMesh->subMeshesComputed() )
1947         theSubComputed = false;
1948     }
1949   }
1950
1951   return aCompound;
1952 }
1953
1954 //=======================================================================
1955 //function : getSimilarAttached
1956 //purpose  : return a hypothesis attached to theShape.
1957 //           If theHyp is provided, similar but not same hypotheses
1958 //           is returned; else only applicable ones having theHypType
1959 //           is returned
1960 //=======================================================================
1961
1962 const SMESH_Hypothesis* SMESH_subMesh::getSimilarAttached(const TopoDS_Shape&      theShape,
1963                                                           const SMESH_Hypothesis * theHyp,
1964                                                           const int                theHypType)
1965 {
1966   SMESH_HypoFilter hypoKind;
1967   hypoKind.Init( hypoKind.HasType( theHyp ? theHyp->GetType() : theHypType ));
1968   if ( theHyp ) {
1969     hypoKind.And   ( hypoKind.HasDim( theHyp->GetDim() ));
1970     hypoKind.AndNot( hypoKind.Is( theHyp ));
1971     if ( theHyp->IsAuxiliary() )
1972       hypoKind.And( hypoKind.HasName( theHyp->GetName() ));
1973     else
1974       hypoKind.AndNot( hypoKind.IsAuxiliary());
1975   }
1976   else {
1977     hypoKind.And( hypoKind.IsApplicableTo( theShape ));
1978   }
1979
1980   return _father->GetHypothesis( theShape, hypoKind, false );
1981 }
1982
1983 //=======================================================================
1984 //function : CheckConcurentHypothesis
1985 //purpose  : check if there are several applicable hypothesis attached to
1986 //           ancestors
1987 //=======================================================================
1988
1989 SMESH_Hypothesis::Hypothesis_Status
1990   SMESH_subMesh::CheckConcurentHypothesis (const int theHypType)
1991 {
1992   MESSAGE ("SMESH_subMesh::CheckConcurentHypothesis");
1993
1994   // is there local hypothesis on me?
1995   if ( getSimilarAttached( _subShape, 0, theHypType ) )
1996     return SMESH_Hypothesis::HYP_OK;
1997
1998
1999   TopoDS_Shape aPrevWithHyp;
2000   const SMESH_Hypothesis* aPrevHyp = 0;
2001   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
2002   for (; it.More(); it.Next())
2003   {
2004     const TopoDS_Shape& ancestor = it.Value();
2005     const SMESH_Hypothesis* hyp = getSimilarAttached( ancestor, 0, theHypType );
2006     if ( hyp )
2007     {
2008       if ( aPrevWithHyp.IsNull() || aPrevWithHyp.IsSame( ancestor ))
2009       {
2010         aPrevWithHyp = ancestor;
2011         aPrevHyp     = hyp;
2012       }
2013       else if ( aPrevWithHyp.ShapeType() == ancestor.ShapeType() && aPrevHyp != hyp )
2014         return SMESH_Hypothesis::HYP_CONCURENT;
2015       else
2016         return SMESH_Hypothesis::HYP_OK;
2017     }
2018   }
2019   return SMESH_Hypothesis::HYP_OK;
2020 }
2021
2022 //================================================================================
2023 /*!
2024  * \brief Constructor of OwnListenerData
2025  */
2026 //================================================================================
2027
2028 SMESH_subMesh::OwnListenerData::OwnListenerData( SMESH_subMesh* sm, EventListener* el):
2029   mySubMesh( sm ),
2030   myMeshID( sm ? sm->GetFather()->GetId() : -1 ),
2031   mySubMeshID( sm ? sm->GetId() : -1 ),
2032   myListener( el )
2033 {
2034 }
2035
2036 //================================================================================
2037 /*!
2038  * \brief Sets an event listener and its data to a submesh
2039  * \param listener - the listener to store
2040  * \param data - the listener data to store
2041  * \param where - the submesh to store the listener and it's data
2042  * 
2043  * It remembers the submesh where it puts the listener in order to delete
2044  * them when HYP_OK algo_state is lost
2045  * After being set, event listener is notified on each event of where submesh.
2046  */
2047 //================================================================================
2048
2049 void SMESH_subMesh::SetEventListener(EventListener*     listener,
2050                                      EventListenerData* data,
2051                                      SMESH_subMesh*     where)
2052 {
2053   if ( listener && where ) {
2054     where->setEventListener( listener, data );
2055     _ownListeners.push_back( OwnListenerData( where, listener ));
2056   }
2057 }
2058
2059 //================================================================================
2060 /*!
2061  * \brief Sets an event listener and its data to a submesh
2062  * \param listener - the listener to store
2063  * \param data - the listener data to store
2064  * 
2065  * After being set, event listener is notified on each event of a submesh.
2066  */
2067 //================================================================================
2068
2069 void SMESH_subMesh::setEventListener(EventListener* listener, EventListenerData* data)
2070 {
2071   map< EventListener*, EventListenerData* >::iterator l_d =
2072     _eventListeners.find( listener );
2073   if ( l_d != _eventListeners.end() ) {
2074     EventListenerData* curData = l_d->second;
2075     if ( curData && curData != data && curData->IsDeletable() )
2076       delete curData;
2077     l_d->second = data;
2078   }
2079   else 
2080     _eventListeners.insert( make_pair( listener, data ));
2081 }
2082
2083 //================================================================================
2084 /*!
2085  * \brief Return an event listener data
2086  * \param listener - the listener whose data is
2087  * \retval EventListenerData* - found data, maybe NULL
2088  */
2089 //================================================================================
2090
2091 EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener) const
2092 {
2093   map< EventListener*, EventListenerData* >::const_iterator l_d =
2094     _eventListeners.find( listener );
2095   if ( l_d != _eventListeners.end() )
2096     return l_d->second;
2097   return 0;
2098 }
2099
2100 //================================================================================
2101 /*!
2102  * \brief Return an event listener data
2103  * \param listenerName - the listener name
2104  * \retval EventListenerData* - found data, maybe NULL
2105  */
2106 //================================================================================
2107
2108 EventListenerData* SMESH_subMesh::GetEventListenerData(const string& listenerName) const
2109 {
2110   map< EventListener*, EventListenerData* >::const_iterator l_d = _eventListeners.begin();
2111   for ( ; l_d != _eventListeners.end(); ++l_d )
2112     if ( listenerName == l_d->first->GetName() )
2113       return l_d->second;
2114   return 0;
2115 }
2116
2117 //================================================================================
2118 /*!
2119  * \brief Notify stored event listeners on the occured event
2120  * \param event - algo_event or compute_event itself
2121  * \param eventType - algo_event or compute_event
2122  * \param hyp - hypothesis, if eventType is algo_event
2123  */
2124 //================================================================================
2125
2126 void SMESH_subMesh::notifyListenersOnEvent( const int         event,
2127                                             const event_type  eventType,
2128                                             SMESH_Hypothesis* hyp)
2129 {
2130   map< EventListener*, EventListenerData* >::iterator l_d = _eventListeners.begin();
2131   for ( ; l_d != _eventListeners.end(); ++l_d )
2132   {
2133     std::pair< EventListener*, EventListenerData* > li_da = *l_d; /* copy to enable removal
2134                                                                      of a listener from
2135                                                                      _eventListeners by
2136                                                                      its ProcessEvent() */
2137     if ( li_da.first->myBusySM.insert( this ).second )
2138     {
2139       li_da.first->ProcessEvent( event, eventType, this, li_da.second, hyp );
2140       li_da.first->myBusySM.erase( this );
2141     }
2142   }
2143 }
2144
2145 //================================================================================
2146 /*!
2147  * \brief Unregister the listener and delete listener's data
2148  * \param listener - the event listener
2149  */
2150 //================================================================================
2151
2152 void SMESH_subMesh::DeleteEventListener(EventListener* listener)
2153 {
2154   map< EventListener*, EventListenerData* >::iterator l_d =
2155     _eventListeners.find( listener );
2156   if ( l_d != _eventListeners.end() ) {
2157     if ( l_d->first && l_d->first->IsDeletable() )
2158     {
2159       l_d->first->BeforeDelete( this, l_d->second );
2160       delete l_d->first;
2161     }
2162     if ( l_d->second && l_d->second->IsDeletable() )
2163     {
2164       delete l_d->second;
2165     }
2166     _eventListeners.erase( l_d );
2167   }
2168 }
2169
2170 //================================================================================
2171 /*!
2172  * \brief Delete event listeners depending on algo of this submesh
2173  */
2174 //================================================================================
2175
2176 void SMESH_subMesh::deleteOwnListeners()
2177 {
2178   list< OwnListenerData >::iterator d;
2179   for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d )
2180   {
2181     if ( !_father->MeshExists( d->myMeshID ))
2182       continue;
2183     if ( _father->GetId() == d->myMeshID && !_father->GetSubMeshContaining( d->mySubMeshID ))
2184       continue;
2185     d->mySubMesh->DeleteEventListener( d->myListener );
2186   }
2187   _ownListeners.clear();
2188 }
2189
2190 //=======================================================================
2191 //function : loadDependentMeshes
2192 //purpose  : loads dependent meshes on SUBMESH_LOADED event
2193 //=======================================================================
2194
2195 void SMESH_subMesh::loadDependentMeshes()
2196 {
2197   list< OwnListenerData >::iterator d;
2198   for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d )
2199     if ( _father != d->mySubMesh->_father )
2200       d->mySubMesh->_father->Load();
2201
2202   // map< EventListener*, EventListenerData* >::iterator l_d = _eventListeners.begin();
2203   // for ( ; l_d != _eventListeners.end(); ++l_d )
2204   //   if ( l_d->second )
2205   //   {
2206   //     const list<SMESH_subMesh*>& smList = l_d->second->mySubMeshes;
2207   //     list<SMESH_subMesh*>::const_iterator sm = smList.begin();
2208   //     for ( ; sm != smList.end(); ++sm )
2209   //       if ( _father != (*sm)->_father )
2210   //         (*sm)->_father->Load();
2211   //   }
2212 }
2213
2214 //================================================================================
2215 /*!
2216  * \brief Do something on a certain event
2217  * \param event - algo_event or compute_event itself
2218  * \param eventType - algo_event or compute_event
2219  * \param subMesh - the submesh where the event occures
2220  * \param data - listener data stored in the subMesh
2221  * \param hyp - hypothesis, if eventType is algo_event
2222  * 
2223  * The base implementation translates CLEAN event to the subMesh
2224  * stored in listener data. Also it sends SUBMESH_COMPUTED event in case of
2225  * successful COMPUTE event.
2226  */
2227 //================================================================================
2228
2229 void SMESH_subMeshEventListener::ProcessEvent(const int          event,
2230                                               const int          eventType,
2231                                               SMESH_subMesh*     subMesh,
2232                                               EventListenerData* data,
2233                                               const SMESH_Hypothesis*  /*hyp*/)
2234 {
2235   if ( data && !data->mySubMeshes.empty() &&
2236        eventType == SMESH_subMesh::COMPUTE_EVENT)
2237   {
2238     ASSERT( data->mySubMeshes.front() != subMesh );
2239     list<SMESH_subMesh*>::iterator smIt = data->mySubMeshes.begin();
2240     list<SMESH_subMesh*>::iterator smEnd = data->mySubMeshes.end();
2241     switch ( event ) {
2242     case SMESH_subMesh::CLEAN:
2243       for ( ; smIt != smEnd; ++ smIt)
2244         (*smIt)->ComputeStateEngine( event );
2245       break;
2246     case SMESH_subMesh::COMPUTE:
2247       if ( subMesh->GetComputeState() == SMESH_subMesh::COMPUTE_OK )
2248         for ( ; smIt != smEnd; ++ smIt)
2249           (*smIt)->ComputeStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
2250       break;
2251     default:;
2252     }
2253   }
2254 }
2255
2256 namespace {
2257
2258   //================================================================================
2259   /*!
2260    * \brief Iterator over submeshes and optionally prepended or appended one
2261    */
2262   //================================================================================
2263
2264   struct _Iterator : public SMDS_Iterator<SMESH_subMesh*>
2265   {
2266     _Iterator(SMDS_Iterator<SMESH_subMesh*>* subIt,
2267               SMESH_subMesh*                 prepend,
2268               SMESH_subMesh*                 append): myIt(subIt),myAppend(append)
2269     {
2270       myCur = prepend ? prepend : myIt->more() ? myIt->next() : append;
2271       if ( myCur == append ) append = 0;
2272     }
2273     /// Return true if and only if there are other object in this iterator
2274     virtual bool more()
2275     {
2276       return myCur;
2277     }
2278     /// Return the current object and step to the next one
2279     virtual SMESH_subMesh* next()
2280     {
2281       SMESH_subMesh* res = myCur;
2282       if ( myIt->more() ) { myCur = myIt->next(); }
2283       else                { myCur = myAppend; myAppend = 0; }
2284       return res;
2285     }
2286     /// ~
2287     ~_Iterator()
2288     { delete myIt; }
2289     ///
2290     SMESH_subMesh                 *myAppend, *myCur;
2291     SMDS_Iterator<SMESH_subMesh*> *myIt;
2292   };
2293 }
2294
2295 //================================================================================
2296 /*!
2297  * \brief  Return iterator on the submeshes this one depends on
2298   * \param includeSelf - this submesh to be returned also
2299   * \param reverse - if true, complex shape submeshes go first
2300  */
2301 //================================================================================
2302
2303 SMESH_subMeshIteratorPtr SMESH_subMesh::getDependsOnIterator(const bool includeSelf,
2304                                                              const bool reverse)
2305 {
2306   SMESH_subMesh *prepend=0, *append=0;
2307   if ( includeSelf ) {
2308     if ( reverse ) prepend = this;
2309     else            append = this;
2310   }
2311   typedef map < int, SMESH_subMesh * > TMap;
2312   if ( reverse )
2313   {
2314     return SMESH_subMeshIteratorPtr
2315       ( new _Iterator( new SMDS_mapReverseIterator<TMap>( DependsOn() ), prepend, append ));
2316   }
2317   {
2318     return SMESH_subMeshIteratorPtr
2319       ( new _Iterator( new SMDS_mapIterator<TMap>( DependsOn() ), prepend, append ));
2320   }
2321 }
2322
2323 //================================================================================
2324 /*!
2325  * \brief  Find common submeshes (based on shared sub-shapes with other
2326   * \param theOther submesh to check
2327   * \param theSetOfCommon set of common submesh
2328  */
2329 //================================================================================
2330
2331 bool SMESH_subMesh::FindIntersection(const SMESH_subMesh* theOther,
2332                                      std::set<const SMESH_subMesh*>& theSetOfCommon ) const
2333 {
2334   int oldNb = theSetOfCommon.size();
2335   // check main submeshes
2336   const map <int, SMESH_subMesh*>::const_iterator otherEnd = theOther->_mapDepend.end();
2337   if ( theOther->_mapDepend.find(this->GetId()) != otherEnd )
2338     theSetOfCommon.insert( this );
2339   if ( _mapDepend.find(theOther->GetId()) != _mapDepend.end() )
2340     theSetOfCommon.insert( theOther );
2341   // check common submeshes
2342   map <int, SMESH_subMesh*>::const_iterator mapIt = _mapDepend.begin();
2343   for( ; mapIt != _mapDepend.end(); mapIt++ )
2344     if ( theOther->_mapDepend.find((*mapIt).first) != otherEnd )
2345       theSetOfCommon.insert( (*mapIt).second );
2346   return oldNb < theSetOfCommon.size();
2347 }