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