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