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