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