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