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