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