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