Salome HOME
83ef5f87c67d5de7f412bcb384678e956a96dcfc
[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   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,
1185                                                        /*complexShapeFirst=*/true);
1186   if ( _father->NbNodes() == 0 )
1187   {
1188     while ( smIt->more() )
1189       smIt->next()->ComputeStateEngine(CHECK_COMPUTE_STATE);
1190   }
1191   else if ( !keepSupportedsubMeshes )
1192   {
1193     while ( smIt->more() )
1194       smIt->next()->ComputeStateEngine(CLEAN);
1195   }
1196   else
1197   {
1198     // find sub-meshes to keep elements on
1199     set< SMESH_subMesh* > smToKeep;
1200     SMESHDS_Mesh* meshDS = _father->GetMeshDS();
1201     while ( smIt->more() )
1202     {
1203       SMESH_subMesh* sm = smIt->next();
1204       if ( sm->IsEmpty() ) continue;
1205
1206       // look for an algo assigned to sm
1207       bool algoFound = false;
1208       const list<const SMESHDS_Hypothesis*>& hyps = meshDS->GetHypothesis( sm->_subShape );
1209       list<const SMESHDS_Hypothesis*>::const_iterator h = hyps.begin();
1210       for ( ; ( !algoFound && h != hyps.end() ); ++h )
1211         algoFound = ((*h)->GetType() != SMESHDS_Hypothesis::PARAM_ALGO );
1212
1213       // remember all sub-meshes of sm
1214       if ( algoFound )
1215       {
1216         SMESH_subMeshIteratorPtr smIt2 = getDependsOnIterator(false,true);
1217         while ( smIt2->more() )
1218           smToKeep.insert( smIt2->next() );
1219       }
1220     }
1221     // remove elements
1222     SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,true);
1223     while ( smIt->more() )
1224     {
1225       SMESH_subMesh* sm = smIt->next();
1226       if ( !smToKeep.count( sm ))
1227         sm->ComputeStateEngine(CLEAN);
1228     }
1229   }
1230 }
1231
1232 //=============================================================================
1233 /*!
1234  *
1235  */
1236 //=============================================================================
1237
1238 void SMESH_subMesh::DumpAlgoState(bool isMain)
1239 {
1240         int dim = SMESH_Gen::GetShapeDim(_subShape);
1241 //   if (dim < 1) return;
1242         if (isMain)
1243         {
1244                 const map < int, SMESH_subMesh * >&subMeshes = DependsOn();
1245
1246                 map < int, SMESH_subMesh * >::const_iterator itsub;
1247                 for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++)
1248                 {
1249                         SMESH_subMesh *sm = (*itsub).second;
1250                         sm->DumpAlgoState(false);
1251                 }
1252         }
1253         int type = _subShape.ShapeType();
1254         MESSAGE("dim = " << dim << " type of shape " << type);
1255         switch (_algoState)
1256         {
1257         case NO_ALGO:
1258                 MESSAGE(" AlgoState = NO_ALGO");
1259                 break;
1260         case MISSING_HYP:
1261                 MESSAGE(" AlgoState = MISSING_HYP");
1262                 break;
1263         case HYP_OK:
1264                 MESSAGE(" AlgoState = HYP_OK");
1265                 break;
1266         }
1267         switch (_computeState)
1268         {
1269         case NOT_READY:
1270                 MESSAGE(" ComputeState = NOT_READY");
1271                 break;
1272         case READY_TO_COMPUTE:
1273                 MESSAGE(" ComputeState = READY_TO_COMPUTE");
1274                 break;
1275         case COMPUTE_OK:
1276                 MESSAGE(" ComputeState = COMPUTE_OK");
1277                 break;
1278         case FAILED_TO_COMPUTE:
1279                 MESSAGE(" ComputeState = FAILED_TO_COMPUTE");
1280                 break;
1281         }
1282 }
1283
1284 //================================================================================
1285 /*!
1286  * \brief Remove nodes and elements bound to submesh
1287   * \param subMesh - submesh containing nodes and elements
1288  */
1289 //================================================================================
1290
1291 static void cleanSubMesh( SMESH_subMesh * subMesh )
1292 {
1293   if (subMesh) {
1294     if (SMESHDS_SubMesh * subMeshDS = subMesh->GetSubMeshDS()) {
1295       SMESHDS_Mesh * meshDS = subMesh->GetFather()->GetMeshDS();
1296       SMDS_ElemIteratorPtr ite = subMeshDS->GetElements();
1297       while (ite->more()) {
1298         const SMDS_MeshElement * elt = ite->next();
1299         //MESSAGE( " RM elt: "<<elt->GetID()<<" ( "<<elt->NbNodes()<<" )" );
1300         //meshDS->RemoveElement(elt);
1301         meshDS->RemoveFreeElement(elt, subMeshDS);
1302       }
1303
1304       SMDS_NodeIteratorPtr itn = subMeshDS->GetNodes();
1305       while (itn->more()) {
1306         const SMDS_MeshNode * node = itn->next();
1307         //MESSAGE( " RM node: "<<node->GetID());
1308         if ( node->NbInverseElements() == 0 )
1309           meshDS->RemoveFreeNode(node, subMeshDS);
1310         else // for StdMeshers_CompositeSegment_1D: node in one submesh, edge in another
1311           meshDS->RemoveNode(node);
1312       }
1313     }
1314   }
1315 }
1316
1317 //=============================================================================
1318 /*!
1319  *
1320  */
1321 //=============================================================================
1322
1323 bool SMESH_subMesh::ComputeStateEngine(int event)
1324 {
1325   switch ( event ) {
1326   case MODIF_ALGO_STATE:
1327   case COMPUTE:
1328     //case COMPUTE_CANCELED:
1329   case CLEAN:
1330     //case SUBMESH_COMPUTED:
1331     //case SUBMESH_RESTORED:
1332     //case SUBMESH_LOADED:
1333     //case MESH_ENTITY_REMOVED:
1334     //case CHECK_COMPUTE_STATE:
1335     _computeError.reset(); break;
1336   default:;
1337   }
1338
1339   if (_subShape.ShapeType() == TopAbs_VERTEX)
1340   {
1341     _computeState = READY_TO_COMPUTE;
1342     SMESHDS_SubMesh* smDS = GetSubMeshDS();
1343     if ( smDS && smDS->NbNodes() ) {
1344       if ( event == CLEAN ) {
1345         cleanDependants();
1346         cleanSubMesh( this );
1347       }
1348       else
1349         _computeState = COMPUTE_OK;
1350     }
1351     else if ( event == COMPUTE && !_alwaysComputed ) {
1352       const TopoDS_Vertex & V = TopoDS::Vertex( _subShape );
1353       gp_Pnt P = BRep_Tool::Pnt(V);
1354       if ( SMDS_MeshNode * n = _father->GetMeshDS()->AddNode(P.X(), P.Y(), P.Z()) ) {
1355         _father->GetMeshDS()->SetNodeOnVertex(n,_Id);
1356         _computeState = COMPUTE_OK;
1357       }
1358     }
1359     if ( event == MODIF_ALGO_STATE )
1360       cleanDependants();
1361     return true;
1362   }
1363   SMESH_Gen *gen = _father->GetGen();
1364   SMESH_Algo *algo = 0;
1365   bool ret = true;
1366   SMESH_Hypothesis::Hypothesis_Status hyp_status;
1367   //algo_state oldAlgoState = (algo_state) GetAlgoState();
1368
1369   switch (_computeState)
1370   {
1371
1372     // ----------------------------------------------------------------------
1373
1374   case NOT_READY:
1375     switch (event)
1376     {
1377     case MODIF_ALGO_STATE:
1378       algo = GetAlgo();
1379       if (algo && !algo->NeedDiscreteBoundary())
1380         cleanDependsOn( algo->SupportSubmeshes() ); // clean sub-meshes with event CLEAN
1381       if ( _algoState == HYP_OK )
1382         _computeState = READY_TO_COMPUTE;
1383       break;
1384     case COMPUTE:               // nothing to do
1385       break;
1386 #ifdef WITH_SMESH_CANCEL_COMPUTE
1387     case COMPUTE_CANCELED:               // nothing to do
1388       break;
1389 #endif
1390     case CLEAN:
1391       cleanDependants();
1392       removeSubMeshElementsAndNodes();
1393       break;
1394     case SUBMESH_COMPUTED:      // nothing to do
1395       break;
1396     case SUBMESH_RESTORED:
1397       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1398       break;
1399     case MESH_ENTITY_REMOVED:
1400       break;
1401     case SUBMESH_LOADED:
1402       loadDependentMeshes();
1403       ComputeSubMeshStateEngine( SUBMESH_LOADED );
1404       //break;
1405     case CHECK_COMPUTE_STATE:
1406       if ( IsMeshComputed() )
1407         _computeState = COMPUTE_OK;
1408       break;
1409     default:
1410       ASSERT(0);
1411       break;
1412     }
1413     break;
1414
1415     // ----------------------------------------------------------------------
1416
1417   case READY_TO_COMPUTE:
1418     switch (event)
1419     {
1420     case MODIF_ALGO_STATE:
1421       _computeState = NOT_READY;
1422       algo = GetAlgo();
1423       if (algo)
1424       {
1425         if (!algo->NeedDiscreteBoundary())
1426           cleanDependsOn( algo->SupportSubmeshes() ); // clean sub-meshes with event CLEAN
1427         if ( _algoState == HYP_OK )
1428           _computeState = READY_TO_COMPUTE;
1429       }
1430       break;
1431     case COMPUTE:
1432       {
1433         algo = GetAlgo();
1434         ASSERT(algo);
1435         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1436         if (!ret)
1437         {
1438           MESSAGE("***** verify compute state *****");
1439           _computeState = NOT_READY;
1440           setAlgoState(MISSING_HYP);
1441           break;
1442         }
1443         TopoDS_Shape shape = _subShape;
1444         // check submeshes needed
1445         if (_father->HasShapeToMesh() ) {
1446           bool subComputed = false, subFailed = false;
1447           if (!algo->OnlyUnaryInput())
1448             shape = getCollection( gen, algo, subComputed, subFailed );
1449           else
1450             subComputed = SubMeshesComputed();
1451           ret = ( algo->NeedDiscreteBoundary() ? subComputed :
1452                   algo->SupportSubmeshes() ? !subFailed :
1453                   ( !subComputed || _father->IsNotConformAllowed() ));
1454           if (!ret)
1455           {
1456             _computeState = FAILED_TO_COMPUTE;
1457             if ( !algo->NeedDiscreteBoundary() && !subFailed )
1458               _computeError =
1459                 SMESH_ComputeError::New(COMPERR_BAD_INPUT_MESH,
1460                                         "Unexpected computed submesh",algo);
1461             break; // goto exit
1462           }
1463         }
1464         // Compute
1465
1466         //cleanDependants(); for "UseExisting_*D" algos
1467         //removeSubMeshElementsAndNodes();
1468         loadDependentMeshes();
1469         ret = false;
1470         _computeState = FAILED_TO_COMPUTE;
1471         _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo);
1472         try {
1473 #if OCC_VERSION_LARGE > 0x06010000
1474           OCC_CATCH_SIGNALS;
1475 #endif
1476           algo->InitComputeError();
1477           MemoryReserve aMemoryReserve;
1478           SMDS_Mesh::CheckMemory();
1479           Kernel_Utils::Localizer loc;
1480           if ( !_father->HasShapeToMesh() ) // no shape
1481           {
1482             SMESH_MesherHelper helper( *_father );
1483             helper.SetSubShape( shape );
1484             helper.SetElementsOnShape( true );
1485             ret = algo->Compute(*_father, &helper );
1486           }
1487           else
1488           {
1489             ret = algo->Compute((*_father), shape);
1490           }
1491           if ( !_computeError || ( !ret && _computeError->IsOK() ) ) // algo can set _computeError of submesh
1492             _computeError = algo->GetComputeError();
1493         }
1494         catch ( ::SMESH_ComputeError& comperr ) {
1495           cout << " SMESH_ComputeError caught" << endl;
1496           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1497           *_computeError = comperr;
1498         }
1499         catch ( std::bad_alloc& exc ) {
1500           MESSAGE("std::bad_alloc thrown inside algo->Compute()");
1501           if ( _computeError ) {
1502             _computeError->myName = COMPERR_MEMORY_PB;
1503             //_computeError->myComment = exc.what();
1504           }
1505           cleanSubMesh( this );
1506           throw exc;
1507         }
1508         catch ( Standard_OutOfMemory& exc ) {
1509           MESSAGE("Standard_OutOfMemory thrown inside algo->Compute()");
1510           if ( _computeError ) {
1511             _computeError->myName = COMPERR_MEMORY_PB;
1512             //_computeError->myComment = exc.what();
1513           }
1514           cleanSubMesh( this );
1515           throw std::bad_alloc();
1516         }
1517         catch (Standard_Failure& ex) {
1518           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1519           _computeError->myName    = COMPERR_OCC_EXCEPTION;
1520           _computeError->myComment += ex.DynamicType()->Name();
1521           if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) {
1522             _computeError->myComment += ": ";
1523             _computeError->myComment += ex.GetMessageString();
1524           }
1525         }
1526         catch ( SALOME_Exception& S_ex ) {
1527           const int skipSalomeShift = 7; /* to skip "Salome " of
1528                                             "Salome Exception" prefix returned
1529                                             by SALOME_Exception::what() */
1530           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1531           _computeError->myName    = COMPERR_SLM_EXCEPTION;
1532           _computeError->myComment = S_ex.what() + skipSalomeShift;
1533         }
1534         catch ( std::exception& exc ) {
1535           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1536           _computeError->myName    = COMPERR_STD_EXCEPTION;
1537           _computeError->myComment = exc.what();
1538         }
1539         catch ( ... ) {
1540           if ( _computeError )
1541             _computeError->myName = COMPERR_EXCEPTION;
1542           else
1543             ret = false;
1544         }
1545         // check if an error reported on any sub-shape
1546         bool isComputeErrorSet = !checkComputeError( algo, ret, shape );
1547         if ( isComputeErrorSet )
1548           ret = false;
1549         // check if anything was built
1550         TopExp_Explorer subS(shape, _subShape.ShapeType());
1551         if (ret)
1552         {
1553           for (; ret && subS.More(); subS.Next())
1554             ret = _father->GetSubMesh( subS.Current() )->IsMeshComputed();
1555         }
1556         // Set _computeError
1557         if (!ret && !isComputeErrorSet)
1558         {
1559           for (subS.ReInit(); subS.More(); subS.Next())
1560           {
1561             SMESH_subMesh* sm = _father->GetSubMesh( subS.Current() );
1562             if ( !sm->IsMeshComputed() )
1563             {
1564               if ( !sm->_computeError )
1565                 sm->_computeError = SMESH_ComputeError::New();
1566               if ( sm->_computeError->IsOK() )
1567                 sm->_computeError->myName = COMPERR_ALGO_FAILED;
1568               sm->_computeState = FAILED_TO_COMPUTE;
1569               sm->_computeError->myAlgo = algo;
1570             }
1571           }
1572         }
1573         if (ret && _computeError && _computeError->myName != COMPERR_WARNING )
1574         {
1575           _computeError.reset();
1576         }
1577
1578         // send event SUBMESH_COMPUTED
1579         if ( ret ) {
1580           if ( !algo->NeedDiscreteBoundary() )
1581             // send SUBMESH_COMPUTED to dependants of all sub-meshes of shape
1582             for (subS.ReInit(); subS.More(); subS.Next())
1583             {
1584               SMESH_subMesh* sm = _father->GetSubMesh( subS.Current() );
1585               SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(false,false);
1586               while ( smIt->more() ) {
1587                 sm = smIt->next();
1588                 if ( sm->GetSubShape().ShapeType() == TopAbs_VERTEX )
1589                   sm->updateDependantsState( SUBMESH_COMPUTED );
1590                 else
1591                   break;
1592               }
1593             }
1594           else
1595             updateDependantsState( SUBMESH_COMPUTED );
1596         }
1597       }
1598       break;
1599 #ifdef WITH_SMESH_CANCEL_COMPUTE
1600     case COMPUTE_CANCELED:               // nothing to do
1601       break;
1602 #endif
1603     case CLEAN:
1604       cleanDependants();
1605       removeSubMeshElementsAndNodes();
1606       _computeState = NOT_READY;
1607       algo = GetAlgo();
1608       if (algo)
1609       {
1610         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1611         if (ret)
1612           _computeState = READY_TO_COMPUTE;
1613         else
1614           setAlgoState(MISSING_HYP);
1615       }
1616       break;
1617     case SUBMESH_COMPUTED:      // nothing to do
1618       break;
1619     case SUBMESH_RESTORED:
1620       // check if a mesh is already computed that may
1621       // happen after retrieval from a file
1622       ComputeStateEngine( CHECK_COMPUTE_STATE );
1623       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1624       algo = GetAlgo();
1625       if (algo) algo->SubmeshRestored( this );
1626       break;
1627     case MESH_ENTITY_REMOVED:
1628       break;
1629     case SUBMESH_LOADED:
1630       loadDependentMeshes();
1631       ComputeSubMeshStateEngine( SUBMESH_LOADED );
1632       //break;
1633     case CHECK_COMPUTE_STATE:
1634       if ( IsMeshComputed() )
1635         _computeState = COMPUTE_OK;
1636       break;
1637     default:
1638       ASSERT(0);
1639       break;
1640     }
1641     break;
1642
1643     // ----------------------------------------------------------------------
1644
1645   case COMPUTE_OK:
1646     switch (event)
1647     {
1648     case MODIF_ALGO_STATE:
1649       ComputeStateEngine( CLEAN );
1650       algo = GetAlgo();
1651       if (algo && !algo->NeedDiscreteBoundary())
1652         cleanDependsOn( algo->SupportSubmeshes() ); // clean sub-meshes with event CLEAN
1653       break;
1654     case COMPUTE:               // nothing to do
1655       break;
1656 #ifdef WITH_SMESH_CANCEL_COMPUTE
1657     case COMPUTE_CANCELED:               // nothing to do
1658       break;
1659 #endif
1660     case CLEAN:
1661       cleanDependants();  // clean sub-meshes, dependant on this one, with event CLEAN
1662       removeSubMeshElementsAndNodes();
1663       _computeState = NOT_READY;
1664       if ( _algoState == HYP_OK )
1665         _computeState = READY_TO_COMPUTE;
1666       break;
1667     case SUBMESH_COMPUTED:      // nothing to do
1668       break;
1669     case SUBMESH_RESTORED:
1670       ComputeStateEngine( CHECK_COMPUTE_STATE );
1671       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1672       algo = GetAlgo();
1673       if (algo) algo->SubmeshRestored( this );
1674       break;
1675     case MESH_ENTITY_REMOVED:
1676       updateDependantsState    ( CHECK_COMPUTE_STATE );
1677       ComputeStateEngine       ( CHECK_COMPUTE_STATE );
1678       ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
1679       break;
1680     case CHECK_COMPUTE_STATE:
1681       if ( !IsMeshComputed() ) {
1682         if (_algoState == HYP_OK)
1683           _computeState = READY_TO_COMPUTE;
1684         else
1685           _computeState = NOT_READY;
1686       }
1687       break;
1688     case SUBMESH_LOADED:
1689       // already treated event, thanks to which _computeState == COMPUTE_OK
1690       break;
1691     default:
1692       ASSERT(0);
1693       break;
1694     }
1695     break;
1696
1697     // ----------------------------------------------------------------------
1698
1699   case FAILED_TO_COMPUTE:
1700     switch (event)
1701     {
1702     case MODIF_ALGO_STATE:
1703       if ( !IsEmpty() )
1704         ComputeStateEngine( CLEAN );
1705       algo = GetAlgo();
1706       if (algo && !algo->NeedDiscreteBoundary())
1707         cleanDependsOn( algo->SupportSubmeshes() ); // clean sub-meshes with event CLEAN
1708       if (_algoState == HYP_OK)
1709         _computeState = READY_TO_COMPUTE;
1710       else
1711         _computeState = NOT_READY;
1712       break;
1713     case COMPUTE:      // nothing to do
1714       break;
1715     case COMPUTE_CANCELED:
1716       {
1717         algo = GetAlgo();
1718         algo->CancelCompute();
1719       }
1720       break;
1721     case CLEAN:
1722       cleanDependants(); // submeshes dependent on me should be cleaned as well
1723       removeSubMeshElementsAndNodes();
1724       break;
1725     case SUBMESH_COMPUTED:      // allow retry compute
1726       if (_algoState == HYP_OK)
1727         _computeState = READY_TO_COMPUTE;
1728       else
1729         _computeState = NOT_READY;
1730       break;
1731     case SUBMESH_RESTORED:
1732       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1733       break;
1734     case MESH_ENTITY_REMOVED:
1735       break;
1736     case CHECK_COMPUTE_STATE:
1737       if ( IsMeshComputed() )
1738         _computeState = COMPUTE_OK;
1739       else
1740         if (_algoState == HYP_OK)
1741           _computeState = READY_TO_COMPUTE;
1742         else
1743           _computeState = NOT_READY;
1744       break;
1745     // case SUBMESH_LOADED:
1746     //   break;
1747     default:
1748       ASSERT(0);
1749       break;
1750     }
1751     break;
1752
1753     // ----------------------------------------------------------------------
1754   default:
1755     ASSERT(0);
1756     break;
1757   }
1758
1759   notifyListenersOnEvent( event, COMPUTE_EVENT );
1760
1761   return ret;
1762 }
1763
1764
1765 //=============================================================================
1766 /*!
1767  *
1768  */
1769 //=============================================================================
1770
1771 bool SMESH_subMesh::Evaluate(MapShapeNbElems& aResMap)
1772 {
1773   _computeError.reset();
1774
1775   bool ret = true;
1776
1777   if (_subShape.ShapeType() == TopAbs_VERTEX) {
1778     vector<int> aVec(SMDSEntity_Last,0);
1779     aVec[SMDSEntity_Node] = 1;
1780     aResMap.insert(make_pair(this,aVec));
1781     return ret;
1782   }
1783
1784   //SMESH_Gen *gen = _father->GetGen();
1785   SMESH_Algo *algo = 0;
1786   SMESH_Hypothesis::Hypothesis_Status hyp_status;
1787
1788   algo = GetAlgo();
1789   if(algo && !aResMap.count(this) )
1790   {
1791     ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1792     if (!ret) return false;
1793
1794     if (_father->HasShapeToMesh() && algo->NeedDiscreteBoundary())
1795     {
1796       // check submeshes needed
1797       bool subMeshEvaluated = true;
1798       int dimToCheck = SMESH_Gen::GetShapeDim( _subShape ) - 1;
1799       SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,/*complexShapeFirst=*/true);
1800       while ( smIt->more() && subMeshEvaluated )
1801       {
1802         SMESH_subMesh* sm = smIt->next();
1803         int dim = SMESH_Gen::GetShapeDim( sm->GetSubShape() );
1804         if (dim < dimToCheck) break; // the rest subMeshes are all of less dimension
1805         const vector<int> & nbs = aResMap[ sm ];
1806         subMeshEvaluated = (std::accumulate( nbs.begin(), nbs.end(), 0 ) > 0 );
1807       }
1808       if ( !subMeshEvaluated )
1809         return false;
1810     }
1811     _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo);
1812     ret = algo->Evaluate((*_father), _subShape, aResMap);
1813
1814     aResMap.insert( make_pair( this,vector<int>(0)));
1815   }
1816
1817   return ret;
1818 }
1819
1820
1821 //=======================================================================
1822 /*!
1823  * \brief Update compute_state by _computeError and send proper events to
1824  * dependent submeshes
1825   * \retval bool - true if _computeError is NOT set
1826  */
1827 //=======================================================================
1828
1829 bool SMESH_subMesh::checkComputeError(SMESH_Algo*         theAlgo,
1830                                       const bool          theComputeOK,
1831                                       const TopoDS_Shape& theShape)
1832 {
1833   bool noErrors = true;
1834
1835   if ( !theShape.IsNull() )
1836   {
1837     // Check state of submeshes
1838     if ( !theAlgo->NeedDiscreteBoundary())
1839     {
1840       SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1841       while ( smIt->more() )
1842         if ( !smIt->next()->checkComputeError( theAlgo, theComputeOK ))
1843           noErrors = false;
1844     }
1845
1846     // Check state of neighbours
1847     if ( !theAlgo->OnlyUnaryInput() &&
1848          theShape.ShapeType() == TopAbs_COMPOUND &&
1849          !theShape.IsSame( _subShape ))
1850     {
1851       for (TopoDS_Iterator subIt( theShape ); subIt.More(); subIt.Next()) {
1852         SMESH_subMesh* sm = _father->GetSubMesh( subIt.Value() );
1853         if ( sm != this ) {
1854           if ( !sm->checkComputeError( theAlgo, theComputeOK, sm->GetSubShape() ))
1855             noErrors = false;
1856           updateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
1857         }
1858       }
1859     }
1860   }
1861   {
1862
1863     // Set my _computeState
1864
1865     if ( !_computeError || _computeError->IsOK() )
1866     {
1867       // no error description is set to this sub-mesh, check if any mesh is computed
1868       _computeState = IsMeshComputed() ? COMPUTE_OK : FAILED_TO_COMPUTE;
1869       if ( _computeState != COMPUTE_OK )
1870       {
1871         if ( _subShape.ShapeType() == TopAbs_EDGE &&
1872              BRep_Tool::Degenerated( TopoDS::Edge( _subShape )) )
1873           _computeState = COMPUTE_OK;
1874         else if ( theComputeOK )
1875           _computeError = SMESH_ComputeError::New(COMPERR_NO_MESH_ON_SHAPE,"",theAlgo);
1876       }
1877     }
1878
1879     if ( _computeError && !_computeError->IsOK() )
1880     {
1881       if ( !_computeError->myAlgo )
1882         _computeError->myAlgo = theAlgo;
1883
1884       // Show error
1885       SMESH_Comment text;
1886       text << theAlgo->GetName() << " failed on sub-shape #" << _Id << " with error ";
1887       if (_computeError->IsCommon() )
1888         text << _computeError->CommonName();
1889       else
1890         text << _computeError->myName;
1891       if ( _computeError->myComment.size() > 0 )
1892         text << " \"" << _computeError->myComment << "\"";
1893
1894       INFOS( text );
1895
1896       _computeState = _computeError->IsKO() ? FAILED_TO_COMPUTE : COMPUTE_OK;
1897
1898       noErrors = false;
1899     }
1900   }
1901   return noErrors;
1902 }
1903
1904 //=======================================================================
1905 //function : updateSubMeshState
1906 //purpose  :
1907 //=======================================================================
1908
1909 void SMESH_subMesh::updateSubMeshState(const compute_state theState)
1910 {
1911   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1912   while ( smIt->more() )
1913     smIt->next()->_computeState = theState;
1914 }
1915
1916 //=======================================================================
1917 //function : ComputeSubMeshStateEngine
1918 //purpose  :
1919 //=======================================================================
1920
1921 void SMESH_subMesh::ComputeSubMeshStateEngine(int event, const bool includeSelf)
1922 {
1923   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(includeSelf,false);
1924   while ( smIt->more() )
1925     smIt->next()->ComputeStateEngine(event);
1926 }
1927
1928 //=======================================================================
1929 //function : updateDependantsState
1930 //purpose  :
1931 //=======================================================================
1932
1933 void SMESH_subMesh::updateDependantsState(const compute_event theEvent)
1934 {
1935   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1936   for (; it.More(); it.Next())
1937   {
1938     const TopoDS_Shape& ancestor = it.Value();
1939     if ( SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor))
1940       aSubMesh->ComputeStateEngine( theEvent );
1941   }
1942 }
1943
1944 //=============================================================================
1945 /*!
1946  *
1947  */
1948 //=============================================================================
1949
1950 void SMESH_subMesh::cleanDependants()
1951 {
1952   int dimToClean = SMESH_Gen::GetShapeDim( _subShape ) + 1;
1953
1954   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
1955   for (; it.More(); it.Next())
1956   {
1957     const TopoDS_Shape& ancestor = it.Value();
1958     if ( SMESH_Gen::GetShapeDim( ancestor ) == dimToClean ) {
1959       // PAL8021. do not go upper than SOLID, else ComputeStateEngine(CLEAN)
1960       // will erase mesh on other shapes in a compound
1961       if ( ancestor.ShapeType() >= TopAbs_SOLID ) {
1962         SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor);
1963         if (aSubMesh &&
1964             !aSubMesh->IsEmpty() ) // prevent infinite CLEAN via event lesteners
1965           aSubMesh->ComputeStateEngine(CLEAN);
1966       }
1967     }
1968   }
1969 }
1970
1971 //=============================================================================
1972 /*!
1973  *
1974  */
1975 //=============================================================================
1976
1977 void SMESH_subMesh::removeSubMeshElementsAndNodes()
1978 {
1979   cleanSubMesh( this );
1980
1981   // algo may bind a submesh not to _subShape, eg 3D algo
1982   // sets nodes on SHELL while _subShape may be SOLID
1983
1984   int dim = SMESH_Gen::GetShapeDim( _subShape );
1985   int type = _subShape.ShapeType() + 1;
1986   for ( ; type <= TopAbs_EDGE; type++) {
1987     if ( dim == SMESH_Gen::GetShapeDim( (TopAbs_ShapeEnum) type ))
1988     {
1989       TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type );
1990       for ( ; exp.More(); exp.Next() )
1991         cleanSubMesh( _father->GetSubMeshContaining( exp.Current() ));
1992     }
1993     else
1994       break;
1995   }
1996 }
1997
1998 //=======================================================================
1999 //function : getCollection
2000 //purpose  : return a shape containing all sub-shapes of the MainShape that can be
2001 //           meshed at once along with _subShape
2002 //=======================================================================
2003
2004 TopoDS_Shape SMESH_subMesh::getCollection(SMESH_Gen * theGen,
2005                                           SMESH_Algo* theAlgo,
2006                                           bool &      theSubComputed,
2007                                           bool &      theSubFailed)
2008 {
2009   theSubComputed = SubMeshesComputed( & theSubFailed );
2010
2011   TopoDS_Shape mainShape = _father->GetMeshDS()->ShapeToMesh();
2012
2013   if ( mainShape.IsSame( _subShape ))
2014     return _subShape;
2015
2016   const bool ignoreAuxiliaryHyps = false;
2017   list<const SMESHDS_Hypothesis*> aUsedHyp =
2018     theAlgo->GetUsedHypothesis( *_father, _subShape, ignoreAuxiliaryHyps ); // copy
2019
2020   // put in a compound all shapes with the same hypothesis assigned
2021   // and a good ComputState
2022
2023   TopoDS_Compound aCompound;
2024   BRep_Builder aBuilder;
2025   aBuilder.MakeCompound( aCompound );
2026
2027   TopExp_Explorer anExplorer( mainShape, _subShape.ShapeType() );
2028   for ( ; anExplorer.More(); anExplorer.Next() )
2029   {
2030     const TopoDS_Shape& S = anExplorer.Current();
2031     SMESH_subMesh* subMesh = _father->GetSubMesh( S );
2032     if ( subMesh == this )
2033     {
2034       aBuilder.Add( aCompound, S );
2035     }
2036     else if ( subMesh->GetComputeState() == READY_TO_COMPUTE )
2037     {
2038       SMESH_Algo* anAlgo = theGen->GetAlgo( *_father, S );
2039       if (strcmp( anAlgo->GetName(), theAlgo->GetName()) == 0 && // same algo
2040           anAlgo->GetUsedHypothesis( *_father, S, ignoreAuxiliaryHyps ) == aUsedHyp) // same hyps
2041         aBuilder.Add( aCompound, S );
2042       if ( !subMesh->SubMeshesComputed() )
2043         theSubComputed = false;
2044     }
2045   }
2046
2047   return aCompound;
2048 }
2049
2050 //=======================================================================
2051 //function : getSimilarAttached
2052 //purpose  : return a hypothesis attached to theShape.
2053 //           If theHyp is provided, similar but not same hypotheses
2054 //           is returned; else only applicable ones having theHypType
2055 //           is returned
2056 //=======================================================================
2057
2058 const SMESH_Hypothesis* SMESH_subMesh::getSimilarAttached(const TopoDS_Shape&      theShape,
2059                                                           const SMESH_Hypothesis * theHyp,
2060                                                           const int                theHypType)
2061 {
2062   SMESH_HypoFilter hypoKind;
2063   hypoKind.Init( hypoKind.HasType( theHyp ? theHyp->GetType() : theHypType ));
2064   if ( theHyp ) {
2065     hypoKind.And   ( hypoKind.HasDim( theHyp->GetDim() ));
2066     hypoKind.AndNot( hypoKind.Is( theHyp ));
2067     if ( theHyp->IsAuxiliary() )
2068       hypoKind.And( hypoKind.HasName( theHyp->GetName() ));
2069     else
2070       hypoKind.AndNot( hypoKind.IsAuxiliary());
2071   }
2072   else {
2073     hypoKind.And( hypoKind.IsApplicableTo( theShape ));
2074   }
2075
2076   return _father->GetHypothesis( theShape, hypoKind, false );
2077 }
2078
2079 //=======================================================================
2080 //function : CheckConcurentHypothesis
2081 //purpose  : check if there are several applicable hypothesis attached to
2082 //           ancestors
2083 //=======================================================================
2084
2085 SMESH_Hypothesis::Hypothesis_Status
2086   SMESH_subMesh::CheckConcurentHypothesis (const int theHypType)
2087 {
2088   MESSAGE ("SMESH_subMesh::CheckConcurentHypothesis");
2089
2090   // is there local hypothesis on me?
2091   if ( getSimilarAttached( _subShape, 0, theHypType ) )
2092     return SMESH_Hypothesis::HYP_OK;
2093
2094
2095   TopoDS_Shape aPrevWithHyp;
2096   const SMESH_Hypothesis* aPrevHyp = 0;
2097   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
2098   for (; it.More(); it.Next())
2099   {
2100     const TopoDS_Shape& ancestor = it.Value();
2101     const SMESH_Hypothesis* hyp = getSimilarAttached( ancestor, 0, theHypType );
2102     if ( hyp )
2103     {
2104       if ( aPrevWithHyp.IsNull() || aPrevWithHyp.IsSame( ancestor ))
2105       {
2106         aPrevWithHyp = ancestor;
2107         aPrevHyp     = hyp;
2108       }
2109       else if ( aPrevWithHyp.ShapeType() == ancestor.ShapeType() && aPrevHyp != hyp )
2110         return SMESH_Hypothesis::HYP_CONCURENT;
2111       else
2112         return SMESH_Hypothesis::HYP_OK;
2113     }
2114   }
2115   return SMESH_Hypothesis::HYP_OK;
2116 }
2117
2118 //================================================================================
2119 /*!
2120  * \brief Constructor of OwnListenerData
2121  */
2122 //================================================================================
2123
2124 SMESH_subMesh::OwnListenerData::OwnListenerData( SMESH_subMesh* sm, EventListener* el):
2125   mySubMesh( sm ),
2126   myMeshID( sm ? sm->GetFather()->GetId() : -1 ),
2127   mySubMeshID( sm ? sm->GetId() : -1 ),
2128   myListener( el )
2129 {
2130 }
2131
2132 //================================================================================
2133 /*!
2134  * \brief Sets an event listener and its data to a submesh
2135  * \param listener - the listener to store
2136  * \param data - the listener data to store
2137  * \param where - the submesh to store the listener and it's data
2138  * 
2139  * It remembers the submesh where it puts the listener in order to delete
2140  * them when HYP_OK algo_state is lost
2141  * After being set, event listener is notified on each event of where submesh.
2142  */
2143 //================================================================================
2144
2145 void SMESH_subMesh::SetEventListener(EventListener*     listener,
2146                                      EventListenerData* data,
2147                                      SMESH_subMesh*     where)
2148 {
2149   if ( listener && where ) {
2150     where->setEventListener( listener, data );
2151     _ownListeners.push_back( OwnListenerData( where, listener ));
2152   }
2153 }
2154
2155 //================================================================================
2156 /*!
2157  * \brief Sets an event listener and its data to a submesh
2158  * \param listener - the listener to store
2159  * \param data - the listener data to store
2160  * 
2161  * After being set, event listener is notified on each event of a submesh.
2162  */
2163 //================================================================================
2164
2165 void SMESH_subMesh::setEventListener(EventListener*     listener,
2166                                      EventListenerData* data)
2167 {
2168   map< EventListener*, EventListenerData* >::iterator l_d =
2169     _eventListeners.find( listener );
2170   if ( l_d != _eventListeners.end() ) {
2171     EventListenerData* curData = l_d->second;
2172     if ( curData && curData != data && curData->IsDeletable() )
2173       delete curData;
2174     l_d->second = data;
2175   }
2176   else
2177   {
2178     for ( l_d = _eventListeners.begin(); l_d != _eventListeners.end(); ++l_d )
2179       if ( listener->GetName() == l_d->first->GetName() )
2180       {
2181         EventListenerData* curData = l_d->second;
2182         if ( curData && curData != data && curData->IsDeletable() )
2183           delete curData;
2184         if ( l_d->first->IsDeletable() )
2185           delete l_d->first;
2186         _eventListeners.erase( l_d );
2187         break;
2188       }
2189     _eventListeners.insert( make_pair( listener, data ));
2190   }
2191 }
2192
2193 //================================================================================
2194 /*!
2195  * \brief Return an event listener data
2196  * \param listener - the listener whose data is
2197  * \retval EventListenerData* - found data, maybe NULL
2198  */
2199 //================================================================================
2200
2201 EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener) const
2202 {
2203   map< EventListener*, EventListenerData* >::const_iterator l_d =
2204     _eventListeners.find( listener );
2205   if ( l_d != _eventListeners.end() )
2206     return l_d->second;
2207   return 0;
2208 }
2209
2210 //================================================================================
2211 /*!
2212  * \brief Return an event listener data
2213  * \param listenerName - the listener name
2214  * \retval EventListenerData* - found data, maybe NULL
2215  */
2216 //================================================================================
2217
2218 EventListenerData* SMESH_subMesh::GetEventListenerData(const string& listenerName) const
2219 {
2220   map< EventListener*, EventListenerData* >::const_iterator l_d = _eventListeners.begin();
2221   for ( ; l_d != _eventListeners.end(); ++l_d )
2222     if ( listenerName == l_d->first->GetName() )
2223       return l_d->second;
2224   return 0;
2225 }
2226
2227 //================================================================================
2228 /*!
2229  * \brief Notify stored event listeners on the occured event
2230  * \param event - algo_event or compute_event itself
2231  * \param eventType - algo_event or compute_event
2232  * \param hyp - hypothesis, if eventType is algo_event
2233  */
2234 //================================================================================
2235
2236 void SMESH_subMesh::notifyListenersOnEvent( const int         event,
2237                                             const event_type  eventType,
2238                                             SMESH_Hypothesis* hyp)
2239 {
2240   map< EventListener*, EventListenerData* >::iterator l_d = _eventListeners.begin();
2241   for ( ; l_d != _eventListeners.end();  )
2242   {
2243     std::pair< EventListener*, EventListenerData* > li_da = *l_d++; /* copy to enable removal
2244                                                                        of a listener from
2245                                                                        _eventListeners by
2246                                                                        its ProcessEvent() */
2247     if ( li_da.first->myBusySM.insert( this ).second )
2248     {
2249       const size_t nbListenersBefore = _eventListeners.size();
2250       li_da.first->ProcessEvent( event, eventType, this, li_da.second, hyp );
2251       if ( nbListenersBefore == _eventListeners.size() )
2252         li_da.first->myBusySM.erase( this ); // a listener hopefully not removed
2253     }
2254   }
2255 }
2256
2257 //================================================================================
2258 /*!
2259  * \brief Unregister the listener and delete listener's data
2260  * \param listener - the event listener
2261  */
2262 //================================================================================
2263
2264 void SMESH_subMesh::DeleteEventListener(EventListener* listener)
2265 {
2266   map< EventListener*, EventListenerData* >::iterator l_d =
2267     _eventListeners.find( listener );
2268   if ( l_d != _eventListeners.end() && l_d->first )
2269   {
2270     if ( l_d->second && l_d->second->IsDeletable() )
2271     {
2272       delete l_d->second;
2273     }
2274     l_d->first->myBusySM.erase( this );
2275     if ( l_d->first->IsDeletable() )
2276     {
2277       l_d->first->BeforeDelete( this, l_d->second );
2278       delete l_d->first;
2279     }
2280     _eventListeners.erase( l_d );
2281   }
2282 }
2283
2284 //================================================================================
2285 /*!
2286  * \brief Delete event listeners depending on algo of this submesh
2287  */
2288 //================================================================================
2289
2290 void SMESH_subMesh::deleteOwnListeners()
2291 {
2292   list< OwnListenerData >::iterator d;
2293   for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d )
2294   {
2295     if ( !_father->MeshExists( d->myMeshID ))
2296       continue;
2297     if ( _father->GetId() == d->myMeshID && !_father->GetSubMeshContaining( d->mySubMeshID ))
2298       continue;
2299     d->mySubMesh->DeleteEventListener( d->myListener );
2300   }
2301   _ownListeners.clear();
2302 }
2303
2304 //=======================================================================
2305 //function : loadDependentMeshes
2306 //purpose  : loads dependent meshes on SUBMESH_LOADED event
2307 //=======================================================================
2308
2309 void SMESH_subMesh::loadDependentMeshes()
2310 {
2311   list< OwnListenerData >::iterator d;
2312   for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d )
2313     if ( _father != d->mySubMesh->_father )
2314       d->mySubMesh->_father->Load();
2315
2316   // map< EventListener*, EventListenerData* >::iterator l_d = _eventListeners.begin();
2317   // for ( ; l_d != _eventListeners.end(); ++l_d )
2318   //   if ( l_d->second )
2319   //   {
2320   //     const list<SMESH_subMesh*>& smList = l_d->second->mySubMeshes;
2321   //     list<SMESH_subMesh*>::const_iterator sm = smList.begin();
2322   //     for ( ; sm != smList.end(); ++sm )
2323   //       if ( _father != (*sm)->_father )
2324   //         (*sm)->_father->Load();
2325   //   }
2326 }
2327
2328 //================================================================================
2329 /*!
2330  * \brief Do something on a certain event
2331  * \param event - algo_event or compute_event itself
2332  * \param eventType - algo_event or compute_event
2333  * \param subMesh - the submesh where the event occures
2334  * \param data - listener data stored in the subMesh
2335  * \param hyp - hypothesis, if eventType is algo_event
2336  * 
2337  * The base implementation translates CLEAN event to the subMesh
2338  * stored in listener data. Also it sends SUBMESH_COMPUTED event in case of
2339  * successful COMPUTE event.
2340  */
2341 //================================================================================
2342
2343 void SMESH_subMeshEventListener::ProcessEvent(const int          event,
2344                                               const int          eventType,
2345                                               SMESH_subMesh*     subMesh,
2346                                               EventListenerData* data,
2347                                               const SMESH_Hypothesis*  /*hyp*/)
2348 {
2349   if ( data && !data->mySubMeshes.empty() &&
2350        eventType == SMESH_subMesh::COMPUTE_EVENT)
2351   {
2352     ASSERT( data->mySubMeshes.front() != subMesh );
2353     list<SMESH_subMesh*>::iterator smIt = data->mySubMeshes.begin();
2354     list<SMESH_subMesh*>::iterator smEnd = data->mySubMeshes.end();
2355     switch ( event ) {
2356     case SMESH_subMesh::CLEAN:
2357       for ( ; smIt != smEnd; ++ smIt)
2358         (*smIt)->ComputeStateEngine( event );
2359       break;
2360     case SMESH_subMesh::COMPUTE:
2361       if ( subMesh->GetComputeState() == SMESH_subMesh::COMPUTE_OK )
2362         for ( ; smIt != smEnd; ++ smIt)
2363           (*smIt)->ComputeStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
2364       break;
2365     default:;
2366     }
2367   }
2368 }
2369
2370 namespace {
2371
2372   //================================================================================
2373   /*!
2374    * \brief Iterator over submeshes and optionally prepended or appended one
2375    */
2376   //================================================================================
2377
2378   struct _Iterator : public SMDS_Iterator<SMESH_subMesh*>
2379   {
2380     _Iterator(SMDS_Iterator<SMESH_subMesh*>* subIt,
2381               SMESH_subMesh*                 prepend,
2382               SMESH_subMesh*                 append): myIt(subIt),myAppend(append)
2383     {
2384       myCur = prepend ? prepend : myIt->more() ? myIt->next() : append;
2385       if ( myCur == append ) append = 0;
2386     }
2387     /// Return true if and only if there are other object in this iterator
2388     virtual bool more()
2389     {
2390       return myCur;
2391     }
2392     /// Return the current object and step to the next one
2393     virtual SMESH_subMesh* next()
2394     {
2395       SMESH_subMesh* res = myCur;
2396       if ( myIt->more() ) { myCur = myIt->next(); }
2397       else                { myCur = myAppend; myAppend = 0; }
2398       return res;
2399     }
2400     /// ~
2401     ~_Iterator()
2402     { delete myIt; }
2403     ///
2404     SMESH_subMesh                 *myAppend, *myCur;
2405     SMDS_Iterator<SMESH_subMesh*> *myIt;
2406   };
2407 }
2408
2409 //================================================================================
2410 /*!
2411  * \brief  Return iterator on the submeshes this one depends on
2412   * \param includeSelf - this submesh to be returned also
2413   * \param reverse - if true, complex shape submeshes go first
2414  */
2415 //================================================================================
2416
2417 SMESH_subMeshIteratorPtr SMESH_subMesh::getDependsOnIterator(const bool includeSelf,
2418                                                              const bool reverse) const
2419 {
2420   SMESH_subMesh *me = (SMESH_subMesh*) this;
2421   SMESH_subMesh *prepend=0, *append=0;
2422   if ( includeSelf ) {
2423     if ( reverse ) prepend = me;
2424     else            append = me;
2425   }
2426   typedef map < int, SMESH_subMesh * > TMap;
2427   if ( reverse )
2428   {
2429     return SMESH_subMeshIteratorPtr
2430       ( new _Iterator( new SMDS_mapReverseIterator<TMap>( me->DependsOn() ), prepend, append ));
2431   }
2432   {
2433     return SMESH_subMeshIteratorPtr
2434       ( new _Iterator( new SMDS_mapIterator<TMap>( me->DependsOn() ), prepend, append ));
2435   }
2436 }
2437
2438 //================================================================================
2439 /*!
2440  * \brief  Find common submeshes (based on shared sub-shapes with other
2441   * \param theOther submesh to check
2442   * \param theSetOfCommon set of common submesh
2443  */
2444 //================================================================================
2445
2446 bool SMESH_subMesh::FindIntersection(const SMESH_subMesh* theOther,
2447                                      std::set<const SMESH_subMesh*>& theSetOfCommon ) const
2448 {
2449   int oldNb = theSetOfCommon.size();
2450   // check main submeshes
2451   const map <int, SMESH_subMesh*>::const_iterator otherEnd = theOther->_mapDepend.end();
2452   if ( theOther->_mapDepend.find(this->GetId()) != otherEnd )
2453     theSetOfCommon.insert( this );
2454   if ( _mapDepend.find(theOther->GetId()) != _mapDepend.end() )
2455     theSetOfCommon.insert( theOther );
2456   // check common submeshes
2457   map <int, SMESH_subMesh*>::const_iterator mapIt = _mapDepend.begin();
2458   for( ; mapIt != _mapDepend.end(); mapIt++ )
2459     if ( theOther->_mapDepend.find((*mapIt).first) != otherEnd )
2460       theSetOfCommon.insert( (*mapIt).second );
2461   return oldNb < theSetOfCommon.size();
2462 }