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