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