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