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