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