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