Salome HOME
8a04a26c19e7dcee865199c99414e96bf1c5dc56
[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   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       TopoDS_Shape algoAssignedTo, otherAssignedTo;
1005       gen->GetAlgo( *_father, _subShape, &algoAssignedTo );
1006       map<int, SMESH_subMesh*>::reverse_iterator i_sm = _mapDepend.rbegin();
1007       for ( ; ( ret == SMESH_Hypothesis::HYP_OK && i_sm != _mapDepend.rend()) ; ++i_sm )
1008         if ( gen->GetAlgo( *_father, i_sm->second->_subShape, &otherAssignedTo ) &&
1009              SMESH_MesherHelper::IsSubShape( /*sub=*/otherAssignedTo, /*main=*/algoAssignedTo ))
1010           ret = SMESH_Hypothesis::HYP_HIDING_ALGO;
1011     }
1012   }
1013
1014   bool stateChange = ( _algoState != oldAlgoState );
1015
1016   if ( stateChange && _algoState == HYP_OK ) // hyp becomes OK
1017     algo->SetEventListener( this );
1018
1019   NotifyListenersOnEvent( event, ALGO_EVENT, anHyp );
1020
1021   if ( stateChange && oldAlgoState == HYP_OK ) { // hyp becomes KO
1022     DeleteOwnListeners();
1023     SetIsAlwaysComputed( false );
1024     if (_subShape.ShapeType() == TopAbs_VERTEX ) {
1025       // restore default states
1026       _algoState = HYP_OK;
1027       _computeState = READY_TO_COMPUTE;
1028     }
1029   }
1030
1031   if ( needFullClean ) {
1032     // added or removed algo is all-dimensional
1033     ComputeStateEngine( CLEAN );
1034     CleanDependsOn();
1035     ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
1036   }
1037
1038   if (stateChange || modifiedHyp)
1039     ComputeStateEngine(MODIF_ALGO_STATE);
1040
1041   return ret;
1042 }
1043
1044 //=======================================================================
1045 //function : IsConform
1046 //purpose  : check if a conform mesh will be produced by the Algo
1047 //=======================================================================
1048
1049 bool SMESH_subMesh::IsConform(const SMESH_Algo* theAlgo)
1050 {
1051 //  MESSAGE( "SMESH_subMesh::IsConform" );
1052   if ( !theAlgo ) return false;
1053
1054   // Suppose that theAlgo is applicable to _subShape, do not check it here
1055   //if ( !IsApplicableHypotesis( theAlgo )) return false;
1056
1057   // check only algo that doesn't NeedDescretBoundary(): because mesh made
1058   // on a sub-shape will be ignored by theAlgo
1059   if ( theAlgo->NeedDescretBoundary() ||
1060        !theAlgo->OnlyUnaryInput() ) // all adjacent shapes will be meshed by this algo?
1061     return true;
1062
1063   SMESH_Gen* gen =_father->GetGen();
1064
1065   // only local algo is to be checked
1066   //if ( gen->IsGlobalHypothesis( theAlgo, *_father ))
1067   if ( _subShape.ShapeType() == _father->GetMeshDS()->ShapeToMesh().ShapeType() )
1068     return true;
1069
1070   // check algo attached to adjacent shapes
1071
1072   // loop on one level down sub-meshes
1073   TopoDS_Iterator itsub( _subShape );
1074   for (; itsub.More(); itsub.Next())
1075   {
1076     // loop on adjacent subShapes
1077     TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( itsub.Value() ));
1078     for (; it.More(); it.Next())
1079     {
1080       const TopoDS_Shape& adjacent = it.Value();
1081       if ( _subShape.IsSame( adjacent )) continue;
1082       if ( adjacent.ShapeType() != _subShape.ShapeType())
1083         break;
1084
1085       // check algo attached to smAdjacent
1086       SMESH_Algo * algo = gen->GetAlgo((*_father), adjacent);
1087       if (algo &&
1088           !algo->NeedDescretBoundary() &&
1089           algo->OnlyUnaryInput())
1090         return false; // NOT CONFORM MESH WILL BE PRODUCED
1091     }
1092   }
1093
1094   return true;
1095 }
1096
1097 //=============================================================================
1098 /*!
1099  *
1100  */
1101 //=============================================================================
1102
1103 void SMESH_subMesh::SetAlgoState(int state)
1104 {
1105   _algoState = state;
1106 }
1107
1108 //=============================================================================
1109 /*!
1110  *
1111  */
1112 //=============================================================================
1113 SMESH_Hypothesis::Hypothesis_Status
1114   SMESH_subMesh::SubMeshesAlgoStateEngine(int event,
1115                                           SMESH_Hypothesis * anHyp)
1116 {
1117   SMESH_Hypothesis::Hypothesis_Status ret = SMESH_Hypothesis::HYP_OK;
1118   //EAP: a wire (dim==1) should notify edges (dim==1)
1119   //EAP: int dim = SMESH_Gen::GetShapeDim(_subShape);
1120   //if (_subShape.ShapeType() < TopAbs_EDGE ) // wire,face etc
1121   {
1122     SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1123     while ( smIt->more() ) {
1124       SMESH_Hypothesis::Hypothesis_Status ret2 =
1125         smIt->next()->AlgoStateEngine(event, anHyp);
1126       if ( ret2 > ret )
1127         ret = ret2;
1128     }
1129   }
1130   return ret;
1131 }
1132
1133 //=============================================================================
1134 /*!
1135  *
1136  */
1137 //=============================================================================
1138
1139 void SMESH_subMesh::CleanDependsOn()
1140 {
1141   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1142   while ( smIt->more() )
1143     smIt->next()->ComputeStateEngine(CLEAN);
1144 }
1145
1146 //=============================================================================
1147 /*!
1148  *
1149  */
1150 //=============================================================================
1151
1152 void SMESH_subMesh::DumpAlgoState(bool isMain)
1153 {
1154         int dim = SMESH_Gen::GetShapeDim(_subShape);
1155 //   if (dim < 1) return;
1156         if (isMain)
1157         {
1158                 const map < int, SMESH_subMesh * >&subMeshes = DependsOn();
1159
1160                 map < int, SMESH_subMesh * >::const_iterator itsub;
1161                 for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++)
1162                 {
1163                         SMESH_subMesh *sm = (*itsub).second;
1164                         sm->DumpAlgoState(false);
1165                 }
1166         }
1167         int type = _subShape.ShapeType();
1168         MESSAGE("dim = " << dim << " type of shape " << type);
1169         switch (_algoState)
1170         {
1171         case NO_ALGO:
1172                 MESSAGE(" AlgoState = NO_ALGO");
1173                 break;
1174         case MISSING_HYP:
1175                 MESSAGE(" AlgoState = MISSING_HYP");
1176                 break;
1177         case HYP_OK:
1178                 MESSAGE(" AlgoState = HYP_OK");
1179                 break;
1180         }
1181         switch (_computeState)
1182         {
1183         case NOT_READY:
1184                 MESSAGE(" ComputeState = NOT_READY");
1185                 break;
1186         case READY_TO_COMPUTE:
1187                 MESSAGE(" ComputeState = READY_TO_COMPUTE");
1188                 break;
1189         case COMPUTE_OK:
1190                 MESSAGE(" ComputeState = COMPUTE_OK");
1191                 break;
1192         case FAILED_TO_COMPUTE:
1193                 MESSAGE(" ComputeState = FAILED_TO_COMPUTE");
1194                 break;
1195         }
1196 }
1197
1198 //================================================================================
1199 /*!
1200  * \brief Remove nodes and elements bound to submesh
1201   * \param subMesh - submesh containing nodes and elements
1202  */
1203 //================================================================================
1204
1205 static void cleanSubMesh( SMESH_subMesh * subMesh )
1206 {
1207   if (subMesh) {
1208     if (SMESHDS_SubMesh * subMeshDS = subMesh->GetSubMeshDS()) {
1209       SMESHDS_Mesh * meshDS = subMesh->GetFather()->GetMeshDS();
1210       SMDS_ElemIteratorPtr ite = subMeshDS->GetElements();
1211       while (ite->more()) {
1212         const SMDS_MeshElement * elt = ite->next();
1213         //MESSAGE( " RM elt: "<<elt->GetID()<<" ( "<<elt->NbNodes()<<" )" );
1214         //meshDS->RemoveElement(elt);
1215         meshDS->RemoveFreeElement(elt, subMeshDS);
1216       }
1217
1218       SMDS_NodeIteratorPtr itn = subMeshDS->GetNodes();
1219       while (itn->more()) {
1220         const SMDS_MeshNode * node = itn->next();
1221         //MESSAGE( " RM node: "<<node->GetID());
1222         if ( node->NbInverseElements() == 0 )
1223           meshDS->RemoveFreeNode(node, subMeshDS);
1224         else // for StdMeshers_CompositeSegment_1D: node in one submesh, edge in another
1225           meshDS->RemoveNode(node);
1226       }
1227     }
1228   }
1229 }
1230
1231 //=============================================================================
1232 /*!
1233  *
1234  */
1235 //=============================================================================
1236
1237 bool SMESH_subMesh::ComputeStateEngine(int event)
1238 {
1239   _computeError.reset();
1240
1241   //MESSAGE("SMESH_subMesh::ComputeStateEngine");
1242   //SCRUTE(_computeState);
1243   //SCRUTE(event);
1244
1245   if (_subShape.ShapeType() == TopAbs_VERTEX)
1246   {
1247     _computeState = READY_TO_COMPUTE;
1248     SMESHDS_SubMesh* smDS = GetSubMeshDS();
1249     if ( smDS && smDS->NbNodes() ) {
1250       if ( event == CLEAN ) {
1251         CleanDependants();
1252         cleanSubMesh( this );
1253       }
1254       else
1255         _computeState = COMPUTE_OK;
1256     }
1257     else if ( event == COMPUTE && !_alwaysComputed ) {
1258       const TopoDS_Vertex & V = TopoDS::Vertex( _subShape );
1259       gp_Pnt P = BRep_Tool::Pnt(V);
1260       if ( SMDS_MeshNode * n = _father->GetMeshDS()->AddNode(P.X(), P.Y(), P.Z()) ) {
1261         _father->GetMeshDS()->SetNodeOnVertex(n,_Id);
1262         _computeState = COMPUTE_OK;
1263       }
1264     }
1265     if ( event == MODIF_ALGO_STATE )
1266       CleanDependants();
1267     return true;
1268   }
1269   SMESH_Gen *gen = _father->GetGen();
1270   SMESH_Algo *algo = 0;
1271   bool ret = true;
1272   SMESH_Hypothesis::Hypothesis_Status hyp_status;
1273   //algo_state oldAlgoState = (algo_state) GetAlgoState();
1274
1275   switch (_computeState)
1276   {
1277
1278     // ----------------------------------------------------------------------
1279
1280   case NOT_READY:
1281     switch (event)
1282     {
1283     case MODIF_ALGO_STATE:
1284       algo = gen->GetAlgo((*_father), _subShape);
1285       if (algo && !algo->NeedDescretBoundary())
1286         CleanDependsOn(); // clean sub-meshes with event CLEAN
1287       if ( _algoState == HYP_OK )
1288         _computeState = READY_TO_COMPUTE;
1289       break;
1290     case COMPUTE:               // nothing to do
1291       break;
1292 #ifdef WITH_SMESH_CANCEL_COMPUTE
1293     case COMPUTE_CANCELED:               // nothing to do
1294       break;
1295 #endif
1296     case CLEAN:
1297       CleanDependants();
1298       RemoveSubMeshElementsAndNodes();
1299       break;
1300     case SUBMESH_COMPUTED:      // nothing to do
1301       break;
1302     case SUBMESH_RESTORED:
1303       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1304       break;
1305     case MESH_ENTITY_REMOVED:
1306       break;
1307     case CHECK_COMPUTE_STATE:
1308       if ( IsMeshComputed() )
1309         _computeState = COMPUTE_OK;
1310       break;
1311     default:
1312       ASSERT(0);
1313       break;
1314     }
1315     break;
1316
1317     // ----------------------------------------------------------------------
1318
1319   case READY_TO_COMPUTE:
1320     switch (event)
1321     {
1322     case MODIF_ALGO_STATE:
1323       _computeState = NOT_READY;
1324       algo = gen->GetAlgo((*_father), _subShape);
1325       if (algo)
1326       {
1327         if (!algo->NeedDescretBoundary())
1328           CleanDependsOn(); // clean sub-meshes with event CLEAN
1329         if ( _algoState == HYP_OK )
1330           _computeState = READY_TO_COMPUTE;
1331       }
1332       break;
1333     case COMPUTE:
1334       {
1335         algo = gen->GetAlgo((*_father), _subShape);
1336         ASSERT(algo);
1337         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1338         if (!ret)
1339         {
1340           MESSAGE("***** verify compute state *****");
1341           _computeState = NOT_READY;
1342           SetAlgoState(MISSING_HYP);
1343           break;
1344         }
1345         TopoDS_Shape shape = _subShape;
1346         // check submeshes needed
1347         if (_father->HasShapeToMesh() ) {
1348           bool subComputed = false;
1349           if (!algo->OnlyUnaryInput())
1350             shape = GetCollection( gen, algo, subComputed );
1351           else
1352             subComputed = SubMeshesComputed();
1353           ret = ( algo->NeedDescretBoundary() ? subComputed :
1354                   algo->SupportSubmeshes() ? true :
1355                   ( !subComputed || _father->IsNotConformAllowed() ));
1356           if (!ret) {
1357             _computeState = FAILED_TO_COMPUTE;
1358             if ( !algo->NeedDescretBoundary() )
1359               _computeError =
1360                 SMESH_ComputeError::New(COMPERR_BAD_INPUT_MESH,
1361                                         "Unexpected computed submesh",algo);
1362             break;
1363           }
1364         }
1365         // compute
1366 //         CleanDependants(); for "UseExisting_*D" algos
1367 //         RemoveSubMeshElementsAndNodes();
1368         ret = false;
1369         _computeState = FAILED_TO_COMPUTE;
1370         _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo);
1371         try {
1372 #if OCC_VERSION_LARGE > 0x06010000
1373           OCC_CATCH_SIGNALS;
1374 #endif
1375           algo->InitComputeError();
1376           MemoryReserve aMemoryReserve;
1377           SMDS_Mesh::CheckMemory();
1378           Kernel_Utils::Localizer loc;
1379           if ( !_father->HasShapeToMesh() ) // no shape
1380           {
1381             SMESH_MesherHelper helper( *_father );
1382             helper.SetSubShape( shape );
1383             helper.SetElementsOnShape( true );
1384             ret = algo->Compute(*_father, &helper );
1385           }
1386           else
1387           {
1388             ret = algo->Compute((*_father), shape);
1389           }
1390           if ( !_computeError || ( !ret && _computeError->IsOK() ) ) // algo can set _computeError of submesh
1391             _computeError = algo->GetComputeError();
1392         }
1393         catch ( std::bad_alloc& exc ) {
1394           MESSAGE("std::bad_alloc thrown inside algo->Compute()");
1395           if ( _computeError ) {
1396             _computeError->myName = COMPERR_MEMORY_PB;
1397             //_computeError->myComment = exc.what();
1398           }
1399           cleanSubMesh( this );
1400           throw exc;
1401         }
1402         catch ( Standard_OutOfMemory& exc ) {
1403           MESSAGE("Standard_OutOfMemory thrown inside algo->Compute()");
1404           if ( _computeError ) {
1405             _computeError->myName = COMPERR_MEMORY_PB;
1406             //_computeError->myComment = exc.what();
1407           }
1408           cleanSubMesh( this );
1409           throw std::bad_alloc();
1410         }
1411         catch (Standard_Failure& ex) {
1412           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1413           _computeError->myName    = COMPERR_OCC_EXCEPTION;
1414           _computeError->myComment += ex.DynamicType()->Name();
1415           if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) {
1416             _computeError->myComment += ": ";
1417             _computeError->myComment += ex.GetMessageString();
1418           }
1419         }
1420         catch ( SALOME_Exception& S_ex ) {
1421           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1422           _computeError->myName    = COMPERR_SLM_EXCEPTION;
1423           _computeError->myComment = S_ex.what();
1424         }
1425         catch ( std::exception& exc ) {
1426           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1427           _computeError->myName    = COMPERR_STD_EXCEPTION;
1428           _computeError->myComment = exc.what();
1429         }
1430         catch ( ... ) {
1431           if ( _computeError )
1432             _computeError->myName = COMPERR_EXCEPTION;
1433           else
1434             ret = false;
1435         }
1436         TopExp_Explorer subS(shape, _subShape.ShapeType());
1437         if (ret) // check if anything was built
1438         {
1439           for (; ret && subS.More(); subS.Next())
1440             ret = _father->GetSubMesh( subS.Current() )->IsMeshComputed();
1441         }
1442         bool isComputeErrorSet = !CheckComputeError( algo, shape );
1443         if (!ret && !isComputeErrorSet)
1444         {
1445           // Set _computeError
1446           for (subS.ReInit(); subS.More(); subS.Next())
1447           {
1448             SMESH_subMesh* sm = _father->GetSubMesh( subS.Current() );
1449             if ( !sm->IsMeshComputed() )
1450             {
1451               if ( !sm->_computeError )
1452                 sm->_computeError = SMESH_ComputeError::New();
1453               if ( sm->_computeError->IsOK() )
1454                 sm->_computeError->myName = COMPERR_ALGO_FAILED;
1455               sm->_computeState = FAILED_TO_COMPUTE;
1456               sm->_computeError->myAlgo = algo;
1457             }
1458           }
1459         }
1460         if (ret && _computeError && _computeError->myName != COMPERR_WARNING )
1461         {
1462           _computeError.reset();
1463         }
1464         UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
1465       }
1466       break;
1467 #ifdef WITH_SMESH_CANCEL_COMPUTE
1468     case COMPUTE_CANCELED:               // nothing to do
1469       break;
1470 #endif
1471     case CLEAN:
1472       CleanDependants();
1473       RemoveSubMeshElementsAndNodes();
1474       _computeState = NOT_READY;
1475       algo = gen->GetAlgo((*_father), _subShape);
1476       if (algo)
1477       {
1478         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1479         if (ret)
1480           _computeState = READY_TO_COMPUTE;
1481         else
1482           SetAlgoState(MISSING_HYP);
1483       }
1484       break;
1485     case SUBMESH_COMPUTED:      // nothing to do
1486       break;
1487     case SUBMESH_RESTORED:
1488       // check if a mesh is already computed that may
1489       // happen after retrieval from a file
1490       ComputeStateEngine( CHECK_COMPUTE_STATE );
1491       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1492       algo = gen->GetAlgo(*_father, _subShape);
1493       if (algo) algo->SubmeshRestored( this );
1494       break;
1495     case MESH_ENTITY_REMOVED:
1496       break;
1497     case CHECK_COMPUTE_STATE:
1498       if ( IsMeshComputed() )
1499         _computeState = COMPUTE_OK;
1500       break;
1501     default:
1502       ASSERT(0);
1503       break;
1504     }
1505     break;
1506
1507     // ----------------------------------------------------------------------
1508
1509   case COMPUTE_OK:
1510     switch (event)
1511     {
1512     case MODIF_ALGO_STATE:
1513       ComputeStateEngine( CLEAN );
1514       algo = gen->GetAlgo((*_father), _subShape);
1515       if (algo && !algo->NeedDescretBoundary())
1516         CleanDependsOn(); // clean sub-meshes with event CLEAN
1517       break;
1518     case COMPUTE:               // nothing to do
1519       break;
1520 #ifdef WITH_SMESH_CANCEL_COMPUTE
1521     case COMPUTE_CANCELED:               // nothing to do
1522       break;
1523 #endif
1524     case CLEAN:
1525       CleanDependants();  // clean sub-meshes, dependant on this one, with event CLEAN
1526       RemoveSubMeshElementsAndNodes();
1527       _computeState = NOT_READY;
1528       if ( _algoState == HYP_OK )
1529         _computeState = READY_TO_COMPUTE;
1530       break;
1531     case SUBMESH_COMPUTED:      // nothing to do
1532       break;
1533     case SUBMESH_RESTORED:
1534       ComputeStateEngine( CHECK_COMPUTE_STATE );
1535       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1536       algo = gen->GetAlgo(*_father, _subShape);
1537       if (algo) algo->SubmeshRestored( this );
1538       break;
1539     case MESH_ENTITY_REMOVED:
1540       UpdateDependantsState( CHECK_COMPUTE_STATE );
1541       ComputeStateEngine( CHECK_COMPUTE_STATE );
1542       ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
1543       break;
1544     case CHECK_COMPUTE_STATE:
1545       if ( !IsMeshComputed() ) {
1546         if (_algoState == HYP_OK)
1547           _computeState = READY_TO_COMPUTE;
1548         else
1549           _computeState = NOT_READY;
1550       }
1551       break;
1552     default:
1553       ASSERT(0);
1554       break;
1555     }
1556     break;
1557
1558     // ----------------------------------------------------------------------
1559
1560   case FAILED_TO_COMPUTE:
1561     switch (event)
1562     {
1563     case MODIF_ALGO_STATE:
1564       if ( !IsEmpty() )
1565         ComputeStateEngine( CLEAN );
1566       algo = gen->GetAlgo((*_father), _subShape);
1567       if (algo && !algo->NeedDescretBoundary())
1568         CleanDependsOn(); // clean sub-meshes with event CLEAN
1569       if (_algoState == HYP_OK)
1570         _computeState = READY_TO_COMPUTE;
1571       else
1572         _computeState = NOT_READY;
1573       break;
1574     case COMPUTE:      // nothing to do
1575       break;
1576 #ifdef WITH_SMESH_CANCEL_COMPUTE
1577     case COMPUTE_CANCELED:
1578       {
1579         algo = gen->GetAlgo((*_father), _subShape);
1580         algo->CancelCompute();
1581       }
1582       break;
1583 #endif
1584     case CLEAN:
1585       CleanDependants(); // submeshes dependent on me should be cleaned as well
1586       RemoveSubMeshElementsAndNodes();
1587       break;
1588     case SUBMESH_COMPUTED:      // allow retry compute
1589       if (_algoState == HYP_OK)
1590         _computeState = READY_TO_COMPUTE;
1591       else
1592         _computeState = NOT_READY;
1593       break;
1594     case SUBMESH_RESTORED:
1595       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1596       break;
1597     case MESH_ENTITY_REMOVED:
1598       break;
1599     case CHECK_COMPUTE_STATE:
1600       if ( IsMeshComputed() )
1601         _computeState = COMPUTE_OK;
1602       else
1603         if (_algoState == HYP_OK)
1604           _computeState = READY_TO_COMPUTE;
1605         else
1606           _computeState = NOT_READY;
1607       break;
1608     default:
1609       ASSERT(0);
1610       break;
1611     }
1612     break;
1613
1614     // ----------------------------------------------------------------------
1615   default:
1616     ASSERT(0);
1617     break;
1618   }
1619
1620   NotifyListenersOnEvent( event, COMPUTE_EVENT );
1621
1622   return ret;
1623 }
1624
1625
1626 //=============================================================================
1627 /*!
1628  *
1629  */
1630 //=============================================================================
1631
1632 bool SMESH_subMesh::Evaluate(MapShapeNbElems& aResMap)
1633 {
1634   _computeError.reset();
1635
1636   bool ret = true;
1637
1638   if (_subShape.ShapeType() == TopAbs_VERTEX) {
1639     vector<int> aVec(SMDSEntity_Last,0);
1640     aVec[SMDSEntity_Node] = 1;
1641     aResMap.insert(make_pair(this,aVec));
1642     return ret;
1643   }
1644
1645   SMESH_Gen *gen = _father->GetGen();
1646   SMESH_Algo *algo = 0;
1647   SMESH_Hypothesis::Hypothesis_Status hyp_status;
1648
1649   algo = gen->GetAlgo((*_father), _subShape);
1650   if(algo && !aResMap.count(this) )
1651   {
1652     ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1653     if (!ret) return false;
1654
1655     if (_father->HasShapeToMesh() && algo->NeedDescretBoundary())
1656     {
1657       // check submeshes needed
1658       bool subMeshEvaluated = true;
1659       int dimToCheck = SMESH_Gen::GetShapeDim( _subShape ) - 1;
1660       SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,/*complexShapeFirst=*/true);
1661       while ( smIt->more() && subMeshEvaluated )
1662       {
1663         SMESH_subMesh* sm = smIt->next();
1664         int dim = SMESH_Gen::GetShapeDim( sm->GetSubShape() );
1665         if (dim < dimToCheck) break; // the rest subMeshes are all of less dimension
1666         const vector<int> & nbs = aResMap[ sm ];
1667         subMeshEvaluated = (std::accumulate( nbs.begin(), nbs.end(), 0 ) > 0 );
1668       }
1669       if ( !subMeshEvaluated )
1670         return false;
1671     }
1672     _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo);
1673     ret = algo->Evaluate((*_father), _subShape, aResMap);
1674
1675     aResMap.insert( make_pair( this,vector<int>(0)));
1676   }
1677
1678   return ret;
1679 }
1680
1681
1682 //=======================================================================
1683 /*!
1684  * \brief Update compute_state by _computeError and send proper events to
1685  * dependent submeshes
1686   * \retval bool - true if _computeError is NOT set
1687  */
1688 //=======================================================================
1689
1690 bool SMESH_subMesh::CheckComputeError(SMESH_Algo* theAlgo, const TopoDS_Shape& theShape)
1691 {
1692   bool noErrors = true;
1693
1694   if ( !theShape.IsNull() )
1695   {
1696     // Check state of submeshes
1697     if ( !theAlgo->NeedDescretBoundary())
1698     {
1699       SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1700       while ( smIt->more() )
1701         if ( !smIt->next()->CheckComputeError( theAlgo ))
1702           noErrors = false;
1703     }
1704
1705     // Check state of neighbours
1706     if ( !theAlgo->OnlyUnaryInput() &&
1707          theShape.ShapeType() == TopAbs_COMPOUND &&
1708          !theShape.IsSame( _subShape ))
1709     {
1710       for (TopoDS_Iterator subIt( theShape ); subIt.More(); subIt.Next()) {
1711         SMESH_subMesh* sm = _father->GetSubMesh( subIt.Value() );
1712         if ( sm != this ) {
1713           if ( !sm->CheckComputeError( theAlgo, sm->GetSubShape() ))
1714             noErrors = false;
1715           UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
1716         }
1717       }
1718     }
1719   }
1720   {
1721     // Check my state
1722     if ( !_computeError || _computeError->IsOK() )
1723     {
1724       // no error description is set to this sub-mesh, check if any mesh is computed
1725       _computeState = IsMeshComputed() ? COMPUTE_OK : FAILED_TO_COMPUTE;
1726     }
1727     else
1728     {
1729       if ( !_computeError->myAlgo )
1730         _computeError->myAlgo = theAlgo;
1731
1732       // Show error
1733       SMESH_Comment text;
1734       text << theAlgo->GetName() << " failed on subshape #" << _Id << " with error ";
1735       if (_computeError->IsCommon() )
1736         text << _computeError->CommonName();
1737       else
1738         text << _computeError->myName;
1739       if ( _computeError->myComment.size() > 0 )
1740         text << " \"" << _computeError->myComment << "\"";
1741
1742       INFOS( text );
1743
1744       _computeState = _computeError->IsKO() ? FAILED_TO_COMPUTE : COMPUTE_OK;
1745
1746       noErrors = false;
1747     }
1748   }
1749   return noErrors;
1750 }
1751
1752 //=======================================================================
1753 //function : UpdateSubMeshState
1754 //purpose  :
1755 //=======================================================================
1756
1757 void SMESH_subMesh::UpdateSubMeshState(const compute_state theState)
1758 {
1759   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1760   while ( smIt->more() )
1761     smIt->next()->_computeState = theState;
1762 }
1763
1764 //=======================================================================
1765 //function : ComputeSubMeshStateEngine
1766 //purpose  :
1767 //=======================================================================
1768
1769 void SMESH_subMesh::ComputeSubMeshStateEngine(int event)
1770 {
1771   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1772   while ( smIt->more() )
1773     smIt->next()->ComputeStateEngine(event);
1774 }
1775
1776 //=======================================================================
1777 //function : UpdateDependantsState
1778 //purpose  :
1779 //=======================================================================
1780
1781 void SMESH_subMesh::UpdateDependantsState(const compute_event theEvent)
1782 {
1783   //MESSAGE("SMESH_subMesh::UpdateDependantsState");
1784   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1785   for (; it.More(); it.Next())
1786   {
1787     const TopoDS_Shape& ancestor = it.Value();
1788     SMESH_subMesh *aSubMesh =
1789       _father->GetSubMeshContaining(ancestor);
1790     if (aSubMesh)
1791       aSubMesh->ComputeStateEngine( theEvent );
1792   }
1793 }
1794
1795 //=============================================================================
1796 /*!
1797  *
1798  */
1799 //=============================================================================
1800
1801 void SMESH_subMesh::CleanDependants()
1802 {
1803   int dimToClean = SMESH_Gen::GetShapeDim( _subShape ) + 1;
1804
1805   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1806   for (; it.More(); it.Next())
1807   {
1808     const TopoDS_Shape& ancestor = it.Value();
1809     if ( SMESH_Gen::GetShapeDim( ancestor ) == dimToClean ) {
1810       // PAL8021. do not go upper than SOLID, else ComputeStateEngine(CLEAN)
1811       // will erase mesh on other shapes in a compound
1812       if ( ancestor.ShapeType() >= TopAbs_SOLID ) {
1813         SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor);
1814         if (aSubMesh)
1815           aSubMesh->ComputeStateEngine(CLEAN);
1816       }
1817     }
1818   }
1819 }
1820
1821 //=============================================================================
1822 /*!
1823  *
1824  */
1825 //=============================================================================
1826
1827 void SMESH_subMesh::RemoveSubMeshElementsAndNodes()
1828 {
1829   //SCRUTE(_subShape.ShapeType());
1830
1831   cleanSubMesh( this );
1832
1833   // algo may bind a submesh not to _subShape, eg 3D algo
1834   // sets nodes on SHELL while _subShape may be SOLID
1835
1836   int dim = SMESH_Gen::GetShapeDim( _subShape );
1837   int type = _subShape.ShapeType() + 1;
1838   for ( ; type <= TopAbs_EDGE; type++) {
1839     if ( dim == SMESH_Gen::GetShapeDim( (TopAbs_ShapeEnum) type ))
1840     {
1841       TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type );
1842       for ( ; exp.More(); exp.Next() )
1843         cleanSubMesh( _father->GetSubMeshContaining( exp.Current() ));
1844     }
1845     else
1846       break;
1847   }
1848 }
1849
1850 //=======================================================================
1851 //function : GetCollection
1852 //purpose  : return a shape containing all sub-shapes of the MainShape that can be
1853 //           meshed at once along with _subShape
1854 //=======================================================================
1855
1856 TopoDS_Shape SMESH_subMesh::GetCollection(SMESH_Gen * theGen,
1857                                           SMESH_Algo* theAlgo,
1858                                           bool &      theSubComputed)
1859 {
1860   MESSAGE("SMESH_subMesh::GetCollection");
1861
1862   theSubComputed = SubMeshesComputed();
1863
1864   TopoDS_Shape mainShape = _father->GetMeshDS()->ShapeToMesh();
1865
1866   if ( mainShape.IsSame( _subShape ))
1867     return _subShape;
1868
1869   const bool ignoreAuxiliaryHyps = false;
1870   list<const SMESHDS_Hypothesis*> aUsedHyp =
1871     theAlgo->GetUsedHypothesis( *_father, _subShape, ignoreAuxiliaryHyps ); // copy
1872
1873   // put in a compound all shapes with the same hypothesis assigned
1874   // and a good ComputState
1875
1876   TopoDS_Compound aCompound;
1877   BRep_Builder aBuilder;
1878   aBuilder.MakeCompound( aCompound );
1879
1880   TopExp_Explorer anExplorer( mainShape, _subShape.ShapeType() );
1881   for ( ; anExplorer.More(); anExplorer.Next() )
1882   {
1883     const TopoDS_Shape& S = anExplorer.Current();
1884     SMESH_subMesh* subMesh = _father->GetSubMesh( S );
1885     if ( subMesh == this )
1886     {
1887       aBuilder.Add( aCompound, S );
1888     }
1889     else if ( subMesh->GetComputeState() == READY_TO_COMPUTE )
1890     {
1891       SMESH_Algo* anAlgo = theGen->GetAlgo( *_father, S );
1892       if (strcmp( anAlgo->GetName(), theAlgo->GetName()) == 0 && // same algo
1893           anAlgo->GetUsedHypothesis( *_father, S, ignoreAuxiliaryHyps ) == aUsedHyp) // same hyps
1894         aBuilder.Add( aCompound, S );
1895       if ( !subMesh->SubMeshesComputed() )
1896         theSubComputed = false;
1897     }
1898   }
1899
1900   return aCompound;
1901 }
1902
1903 //=======================================================================
1904 //function : GetSimilarAttached
1905 //purpose  : return a hypothesis attached to theShape.
1906 //           If theHyp is provided, similar but not same hypotheses
1907 //           is returned; else only applicable ones having theHypType
1908 //           is returned
1909 //=======================================================================
1910
1911 const SMESH_Hypothesis* SMESH_subMesh::GetSimilarAttached(const TopoDS_Shape&      theShape,
1912                                                           const SMESH_Hypothesis * theHyp,
1913                                                           const int                theHypType)
1914 {
1915   SMESH_HypoFilter hypoKind;
1916   hypoKind.Init( hypoKind.HasType( theHyp ? theHyp->GetType() : theHypType ));
1917   if ( theHyp ) {
1918     hypoKind.And   ( hypoKind.HasDim( theHyp->GetDim() ));
1919     hypoKind.AndNot( hypoKind.Is( theHyp ));
1920     if ( theHyp->IsAuxiliary() )
1921       hypoKind.And( hypoKind.HasName( theHyp->GetName() ));
1922     else
1923       hypoKind.AndNot( hypoKind.IsAuxiliary());
1924   }
1925   else {
1926     hypoKind.And( hypoKind.IsApplicableTo( theShape ));
1927   }
1928
1929   return _father->GetHypothesis( theShape, hypoKind, false );
1930 }
1931
1932 //=======================================================================
1933 //function : CheckConcurentHypothesis
1934 //purpose  : check if there are several applicable hypothesis attached to
1935 //           ancestors
1936 //=======================================================================
1937
1938 SMESH_Hypothesis::Hypothesis_Status
1939   SMESH_subMesh::CheckConcurentHypothesis (const int theHypType)
1940 {
1941   MESSAGE ("SMESH_subMesh::CheckConcurentHypothesis");
1942
1943   // is there local hypothesis on me?
1944   if ( GetSimilarAttached( _subShape, 0, theHypType ) )
1945     return SMESH_Hypothesis::HYP_OK;
1946
1947
1948   TopoDS_Shape aPrevWithHyp;
1949   const SMESH_Hypothesis* aPrevHyp = 0;
1950   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1951   for (; it.More(); it.Next())
1952   {
1953     const TopoDS_Shape& ancestor = it.Value();
1954     const SMESH_Hypothesis* hyp = GetSimilarAttached( ancestor, 0, theHypType );
1955     if ( hyp )
1956     {
1957       if ( aPrevWithHyp.IsNull() || aPrevWithHyp.IsSame( ancestor ))
1958       {
1959         aPrevWithHyp = ancestor;
1960         aPrevHyp     = hyp;
1961       }
1962       else if ( aPrevWithHyp.ShapeType() == ancestor.ShapeType() && aPrevHyp != hyp )
1963         return SMESH_Hypothesis::HYP_CONCURENT;
1964       else
1965         return SMESH_Hypothesis::HYP_OK;
1966     }
1967   }
1968   return SMESH_Hypothesis::HYP_OK;
1969 }
1970
1971 //================================================================================
1972 /*!
1973  * \brief Sets an event listener and its data to a submesh
1974  * \param listener - the listener to store
1975  * \param data - the listener data to store
1976  * \param where - the submesh to store the listener and it's data
1977  * \param deleteListener - if true then the listener will be deleted as
1978  *        it is removed from where submesh
1979  * 
1980  * It remembers the submesh where it puts the listener in order to delete
1981  * them when HYP_OK algo_state is lost
1982  * After being set, event listener is notified on each event of where submesh.
1983  */
1984 //================================================================================
1985
1986 void SMESH_subMesh::SetEventListener(EventListener*     listener,
1987                                      EventListenerData* data,
1988                                      SMESH_subMesh*     where)
1989 {
1990   if ( listener && where ) {
1991     where->SetEventListener( listener, data );
1992     myOwnListeners.push_back( make_pair( where, listener ));
1993   }
1994 }
1995
1996 //================================================================================
1997 /*!
1998  * \brief Sets an event listener and its data to a submesh
1999  * \param listener - the listener to store
2000  * \param data - the listener data to store
2001  * 
2002  * After being set, event listener is notified on each event of a submesh.
2003  */
2004 //================================================================================
2005
2006 void SMESH_subMesh::SetEventListener(EventListener* listener, EventListenerData* data)
2007 {
2008   map< EventListener*, EventListenerData* >::iterator l_d =
2009     myEventListeners.find( listener );
2010   if ( l_d != myEventListeners.end() ) {
2011     EventListenerData* curData = l_d->second;
2012     if ( curData && curData != data && curData->IsDeletable() )
2013       delete curData;
2014     l_d->second = data;
2015   }
2016   else 
2017     myEventListeners.insert( make_pair( listener, data ));
2018 }
2019
2020 //================================================================================
2021 /*!
2022  * \brief Return an event listener data
2023  * \param listener - the listener whose data is
2024  * \retval EventListenerData* - found data, maybe NULL
2025  */
2026 //================================================================================
2027
2028 EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener) const
2029 {
2030   map< EventListener*, EventListenerData* >::const_iterator l_d =
2031     myEventListeners.find( listener );
2032   if ( l_d != myEventListeners.end() )
2033     return l_d->second;
2034   return 0;
2035 }
2036
2037 //================================================================================
2038 /*!
2039  * \brief Notify stored event listeners on the occured event
2040  * \param event - algo_event or compute_event itself
2041  * \param eventType - algo_event or compute_event
2042  * \param hyp - hypothesis, if eventType is algo_event
2043  */
2044 //================================================================================
2045
2046 void SMESH_subMesh::NotifyListenersOnEvent( const int         event,
2047                                             const event_type  eventType,
2048                                             SMESH_Hypothesis* hyp)
2049 {
2050   map< EventListener*, EventListenerData* >::iterator l_d = myEventListeners.begin();
2051   for ( ; l_d != myEventListeners.end(); ++l_d )
2052     if ( (*l_d).first->myBusySM.insert( this ).second )
2053     {
2054       l_d->first->ProcessEvent( event, eventType, this, l_d->second, hyp );
2055       l_d->first->myBusySM.erase( this );
2056     }
2057 }
2058
2059 //================================================================================
2060 /*!
2061  * \brief Unregister the listener and delete listener's data
2062  * \param listener - the event listener
2063  */
2064 //================================================================================
2065
2066 void SMESH_subMesh::DeleteEventListener(EventListener* listener)
2067 {
2068   map< EventListener*, EventListenerData* >::iterator l_d =
2069     myEventListeners.find( listener );
2070   if ( l_d != myEventListeners.end() ) {
2071     if ( l_d->first  && l_d->first->IsDeletable() )  delete l_d->first;
2072     if ( l_d->second && l_d->second->IsDeletable() ) delete l_d->second;
2073     myEventListeners.erase( l_d );
2074   }
2075 }
2076
2077 //================================================================================
2078 /*!
2079  * \brief Delete event listeners depending on algo of this submesh
2080  */
2081 //================================================================================
2082
2083 void SMESH_subMesh::DeleteOwnListeners()
2084 {
2085   list< pair< SMESH_subMesh*, EventListener* > >::iterator sm_l;
2086   for ( sm_l = myOwnListeners.begin(); sm_l != myOwnListeners.end(); ++sm_l)
2087     sm_l->first->DeleteEventListener( sm_l->second );
2088   myOwnListeners.clear();
2089 }
2090
2091 //================================================================================
2092 /*!
2093  * \brief Do something on a certain event
2094  * \param event - algo_event or compute_event itself
2095  * \param eventType - algo_event or compute_event
2096  * \param subMesh - the submesh where the event occures
2097  * \param data - listener data stored in the subMesh
2098  * \param hyp - hypothesis, if eventType is algo_event
2099  * 
2100  * The base implementation translates CLEAN event to the subMesh
2101  * stored in listener data. Also it sends SUBMESH_COMPUTED event in case of
2102  * successful COMPUTE event.
2103  */
2104 //================================================================================
2105
2106 void SMESH_subMeshEventListener::ProcessEvent(const int          event,
2107                                               const int          eventType,
2108                                               SMESH_subMesh*     subMesh,
2109                                               EventListenerData* data,
2110                                               const SMESH_Hypothesis*  /*hyp*/)
2111 {
2112   if ( data && !data->mySubMeshes.empty() &&
2113        eventType == SMESH_subMesh::COMPUTE_EVENT)
2114   {
2115     ASSERT( data->mySubMeshes.front() != subMesh );
2116     list<SMESH_subMesh*>::iterator smIt = data->mySubMeshes.begin();
2117     list<SMESH_subMesh*>::iterator smEnd = data->mySubMeshes.end();
2118     switch ( event ) {
2119     case SMESH_subMesh::CLEAN:
2120       for ( ; smIt != smEnd; ++ smIt)
2121         (*smIt)->ComputeStateEngine( event );
2122       break;
2123     case SMESH_subMesh::COMPUTE:
2124       if ( subMesh->GetComputeState() == SMESH_subMesh::COMPUTE_OK )
2125         for ( ; smIt != smEnd; ++ smIt)
2126           (*smIt)->ComputeStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
2127       break;
2128     default:;
2129     }
2130   }
2131 }
2132
2133 namespace {
2134
2135   //================================================================================
2136   /*!
2137    * \brief Iterator over submeshes and optionally prepended or appended one
2138    */
2139   //================================================================================
2140
2141   struct _Iterator : public SMDS_Iterator<SMESH_subMesh*>
2142   {
2143     _Iterator(SMDS_Iterator<SMESH_subMesh*>* subIt,
2144               SMESH_subMesh*                 prepend,
2145               SMESH_subMesh*                 append): myIt(subIt),myAppend(append)
2146     {
2147       myCur = prepend ? prepend : myIt->more() ? myIt->next() : append;
2148       if ( myCur == append ) append = 0;
2149     }
2150     /// Return true if and only if there are other object in this iterator
2151     virtual bool more()
2152     {
2153       return myCur;
2154     }
2155     /// Return the current object and step to the next one
2156     virtual SMESH_subMesh* next()
2157     {
2158       SMESH_subMesh* res = myCur;
2159       if ( myIt->more() ) { myCur = myIt->next(); }
2160       else                { myCur = myAppend; myAppend = 0; }
2161       return res;
2162     }
2163     /// ~
2164     ~_Iterator()
2165     { delete myIt; }
2166     ///
2167     SMESH_subMesh                 *myAppend, *myCur;
2168     SMDS_Iterator<SMESH_subMesh*> *myIt;
2169   };
2170 }
2171
2172 //================================================================================
2173 /*!
2174  * \brief  Return iterator on the submeshes this one depends on
2175   * \param includeSelf - this submesh to be returned also
2176   * \param reverse - if true, complex shape submeshes go first
2177  */
2178 //================================================================================
2179
2180 SMESH_subMeshIteratorPtr SMESH_subMesh::getDependsOnIterator(const bool includeSelf,
2181                                                              const bool reverse)
2182 {
2183   SMESH_subMesh *prepend=0, *append=0;
2184   if ( includeSelf ) {
2185     if ( reverse ) prepend = this;
2186     else            append = this;
2187   }
2188   typedef map < int, SMESH_subMesh * > TMap;
2189   if ( reverse )
2190   {
2191     return SMESH_subMeshIteratorPtr
2192       ( new _Iterator( new SMDS_mapReverseIterator<TMap>( DependsOn() ), prepend, append ));
2193   }
2194   {
2195     return SMESH_subMeshIteratorPtr
2196       ( new _Iterator( new SMDS_mapIterator<TMap>( DependsOn() ), prepend, append ));
2197   }
2198 }
2199
2200 //================================================================================
2201 /*!
2202  * \brief  Find common submeshes (based on shared subshapes with other
2203   * \param theOther submesh to check
2204   * \param theSetOfCommon set of common submesh
2205  */
2206 //================================================================================
2207
2208 bool SMESH_subMesh::FindIntersection(const SMESH_subMesh* theOther,
2209                                      std::set<const SMESH_subMesh*>& theSetOfCommon ) const
2210 {
2211   int oldNb = theSetOfCommon.size();
2212   // check main submeshes
2213   const map <int, SMESH_subMesh*>::const_iterator otherEnd = theOther->_mapDepend.end();
2214   if ( theOther->_mapDepend.find(this->GetId()) != otherEnd )
2215     theSetOfCommon.insert( this );
2216   if ( _mapDepend.find(theOther->GetId()) != _mapDepend.end() )
2217     theSetOfCommon.insert( theOther );
2218   // check common submeshes
2219   map <int, SMESH_subMesh*>::const_iterator mapIt = _mapDepend.begin();
2220   for( ; mapIt != _mapDepend.end(); mapIt++ )
2221     if ( theOther->_mapDepend.find((*mapIt).first) != otherEnd )
2222       theSetOfCommon.insert( (*mapIt).second );
2223   return oldNb < theSetOfCommon.size();
2224 }