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