Salome HOME
Merge branch V7_3_1_BR
[modules/smesh.git] / src / SMESH / SMESH_subMesh.cxx
1 // Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SMESH SMESH : implementaion of SMESH idl descriptions
24 //  File   : SMESH_subMesh.cxx
25 //  Author : Paul RASCLE, EDF
26 //  Module : SMESH
27
28 #include "SMESH_subMesh.hxx"
29
30 #include "SMESH_Algo.hxx"
31 #include "SMESH_Gen.hxx"
32 #include "SMESH_HypoFilter.hxx"
33 #include "SMESH_Hypothesis.hxx"
34 #include "SMESH_Mesh.hxx"
35 #include "SMESH_MesherHelper.hxx"
36 #include "SMESH_subMeshEventListener.hxx"
37 #include "SMESH_Comment.hxx"
38 #include "SMDS_SetIterator.hxx"
39 #include "SMDSAbs_ElementType.hxx"
40
41 #include <Basics_OCCTVersion.hxx>
42
43 #include "utilities.h"
44 #include "OpUtil.hxx"
45 #include "Basics_Utils.hxx"
46
47 #include <BRep_Builder.hxx>
48 #include <BRep_Tool.hxx>
49 #include <TopExp.hxx>
50 #include <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 = 5000; break;
389     case TopAbs_FACE:  computeCost = 500; break;
390     case TopAbs_EDGE:  computeCost = 2; 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, 0);
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, 0);
1393         else // for StdMeshers_CompositeSegment_1D: node in one submesh, edge in another
1394           meshDS->RemoveNode(node);
1395       }
1396       subMeshDS->Clear();
1397     }
1398   }
1399 }
1400
1401 //=============================================================================
1402 /*!
1403  *
1404  */
1405 //=============================================================================
1406
1407 bool SMESH_subMesh::ComputeStateEngine(int event)
1408 {
1409   switch ( event ) {
1410   case MODIF_ALGO_STATE:
1411   case COMPUTE:
1412   case COMPUTE_SUBMESH:
1413     //case COMPUTE_CANCELED:
1414   case CLEAN:
1415     //case SUBMESH_COMPUTED:
1416     //case SUBMESH_RESTORED:
1417     //case SUBMESH_LOADED:
1418     //case MESH_ENTITY_REMOVED:
1419     //case CHECK_COMPUTE_STATE:
1420     _computeError.reset(); break;
1421   default:;
1422   }
1423
1424   if ( event == CLEAN )
1425     _alwaysComputed = false; // Unset 'true' set by MergeNodes() (issue 0022182)
1426
1427   if (_subShape.ShapeType() == TopAbs_VERTEX)
1428   {
1429     _computeState = READY_TO_COMPUTE;
1430     SMESHDS_SubMesh* smDS = GetSubMeshDS();
1431     if ( smDS && smDS->NbNodes() )
1432     {
1433       if ( event == CLEAN ) {
1434         cleanDependants();
1435         cleanSubMesh( this );
1436       }
1437       else
1438         _computeState = COMPUTE_OK;
1439     }
1440     else if (( event == COMPUTE || event == COMPUTE_SUBMESH )
1441              && !_alwaysComputed )
1442     {
1443       const TopoDS_Vertex & V = TopoDS::Vertex( _subShape );
1444       gp_Pnt P = BRep_Tool::Pnt(V);
1445       if ( SMDS_MeshNode * n = _father->GetMeshDS()->AddNode(P.X(), P.Y(), P.Z()) ) {
1446         _father->GetMeshDS()->SetNodeOnVertex(n,_Id);
1447         _computeState = COMPUTE_OK;
1448       }
1449     }
1450     if ( event == MODIF_ALGO_STATE )
1451       cleanDependants();
1452     return true;
1453   }
1454   SMESH_Gen *gen = _father->GetGen();
1455   SMESH_Algo *algo = 0;
1456   bool ret = true;
1457   SMESH_Hypothesis::Hypothesis_Status hyp_status;
1458   //algo_state oldAlgoState = (algo_state) GetAlgoState();
1459
1460   switch (_computeState)
1461   {
1462
1463     // ----------------------------------------------------------------------
1464
1465   case NOT_READY:
1466     switch (event)
1467     {
1468     case MODIF_ALGO_STATE:
1469       algo = GetAlgo();
1470       if (algo && !algo->NeedDiscreteBoundary())
1471         cleanDependsOn( algo ); // clean sub-meshes with event CLEAN
1472       if ( _algoState == HYP_OK )
1473         _computeState = READY_TO_COMPUTE;
1474       break;
1475     case COMPUTE:               // nothing to do
1476     case COMPUTE_SUBMESH:
1477       break;
1478     case COMPUTE_CANCELED:      // nothing to do
1479       break;
1480     case CLEAN:
1481       cleanDependants();
1482       removeSubMeshElementsAndNodes();
1483       break;
1484     case SUBMESH_COMPUTED:      // nothing to do
1485       break;
1486     case SUBMESH_RESTORED:
1487       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1488       break;
1489     case MESH_ENTITY_REMOVED:
1490       break;
1491     case SUBMESH_LOADED:
1492       loadDependentMeshes();
1493       ComputeSubMeshStateEngine( SUBMESH_LOADED );
1494       //break;
1495     case CHECK_COMPUTE_STATE:
1496       if ( IsMeshComputed() )
1497         _computeState = COMPUTE_OK;
1498       break;
1499     default:
1500       ASSERT(0);
1501       break;
1502     }
1503     break;
1504
1505     // ----------------------------------------------------------------------
1506
1507   case READY_TO_COMPUTE:
1508     switch (event)
1509     {
1510     case MODIF_ALGO_STATE:
1511       _computeState = NOT_READY;
1512       algo = GetAlgo();
1513       if (algo)
1514       {
1515         if (!algo->NeedDiscreteBoundary())
1516           cleanDependsOn( algo ); // clean sub-meshes with event CLEAN
1517         if ( _algoState == HYP_OK )
1518           _computeState = READY_TO_COMPUTE;
1519       }
1520       break;
1521     case COMPUTE:
1522     case COMPUTE_SUBMESH:
1523       {
1524         algo = GetAlgo();
1525         ASSERT(algo);
1526         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1527         if (!ret)
1528         {
1529           MESSAGE("***** verify compute state *****");
1530           _computeState = NOT_READY;
1531           setAlgoState(MISSING_HYP);
1532           break;
1533         }
1534         TopoDS_Shape shape = _subShape;
1535         algo->SubMeshesToCompute().assign( 1, this );
1536         // check submeshes needed
1537         if (_father->HasShapeToMesh() ) {
1538           bool subComputed = false, subFailed = false;
1539           if (!algo->OnlyUnaryInput()) {
1540             if ( event == COMPUTE /*&&
1541                  ( algo->NeedDiscreteBoundary() || algo->SupportSubmeshes() )*/)
1542               shape = getCollection( gen, algo, subComputed, subFailed, algo->SubMeshesToCompute());
1543             else
1544               subComputed = SubMeshesComputed( & subFailed );
1545           }
1546           else {
1547             subComputed = SubMeshesComputed();
1548           }
1549           ret = ( algo->NeedDiscreteBoundary() ? subComputed :
1550                   algo->SupportSubmeshes() ? !subFailed :
1551                   ( !subComputed || _father->IsNotConformAllowed() ));
1552           if (!ret)
1553           {
1554             _computeState = FAILED_TO_COMPUTE;
1555             if ( !algo->NeedDiscreteBoundary() && !subFailed )
1556               _computeError =
1557                 SMESH_ComputeError::New(COMPERR_BAD_INPUT_MESH,
1558                                         "Unexpected computed submesh",algo);
1559             break; // goto exit
1560           }
1561         }
1562         // Compute
1563
1564         // to restore cout that may be redirected by algo
1565         std::streambuf* coutBuffer = std::cout.rdbuf();
1566
1567         //cleanDependants(); for "UseExisting_*D" algos
1568         //removeSubMeshElementsAndNodes();
1569         loadDependentMeshes();
1570         ret = false;
1571         _computeState = FAILED_TO_COMPUTE;
1572         _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo);
1573         try {
1574           OCC_CATCH_SIGNALS;
1575
1576           algo->InitComputeError();
1577
1578           MemoryReserve aMemoryReserve;
1579           SMDS_Mesh::CheckMemory();
1580           Kernel_Utils::Localizer loc;
1581           if ( !_father->HasShapeToMesh() ) // no shape
1582           {
1583             SMESH_MesherHelper helper( *_father );
1584             helper.SetSubShape( shape );
1585             helper.SetElementsOnShape( true );
1586             ret = algo->Compute(*_father, &helper );
1587           }
1588           else
1589           {
1590             ret = algo->Compute((*_father), shape);
1591           }
1592           if ( !_computeError || (/* !ret && */_computeError->IsOK() ) ) // algo can set _computeError of submesh
1593             _computeError = algo->GetComputeError();
1594         }
1595         catch ( ::SMESH_ComputeError& comperr ) {
1596           cout << " SMESH_ComputeError caught" << endl;
1597           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1598           *_computeError = comperr;
1599         }
1600         catch ( std::bad_alloc& exc ) {
1601           MESSAGE("std::bad_alloc thrown inside algo->Compute()");
1602           if ( _computeError ) {
1603             _computeError->myName = COMPERR_MEMORY_PB;
1604             //_computeError->myComment = exc.what();
1605           }
1606           cleanSubMesh( this );
1607           throw exc;
1608         }
1609         catch ( Standard_OutOfMemory& exc ) {
1610           MESSAGE("Standard_OutOfMemory thrown inside algo->Compute()");
1611           if ( _computeError ) {
1612             _computeError->myName = COMPERR_MEMORY_PB;
1613             //_computeError->myComment = exc.what();
1614           }
1615           cleanSubMesh( this );
1616           throw std::bad_alloc();
1617         }
1618         catch (Standard_Failure& ex) {
1619           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1620           _computeError->myName    = COMPERR_OCC_EXCEPTION;
1621           _computeError->myComment += ex.DynamicType()->Name();
1622           if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) {
1623             _computeError->myComment += ": ";
1624             _computeError->myComment += ex.GetMessageString();
1625           }
1626         }
1627         catch ( SALOME_Exception& S_ex ) {
1628           const int skipSalomeShift = 7; /* to skip "Salome " of
1629                                             "Salome Exception" prefix returned
1630                                             by SALOME_Exception::what() */
1631           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1632           _computeError->myName    = COMPERR_SLM_EXCEPTION;
1633           _computeError->myComment = S_ex.what() + skipSalomeShift;
1634         }
1635         catch ( std::exception& exc ) {
1636           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1637           _computeError->myName    = COMPERR_STD_EXCEPTION;
1638           _computeError->myComment = exc.what();
1639         }
1640         catch ( ... ) {
1641           if ( _computeError )
1642             _computeError->myName = COMPERR_EXCEPTION;
1643           else
1644             ret = false;
1645         }
1646         std::cout.rdbuf( coutBuffer ); // restore cout that could be redirected by algo
1647
1648         // check if an error reported on any sub-shape
1649         bool isComputeErrorSet = !checkComputeError( algo, ret, shape );
1650         if ( isComputeErrorSet )
1651           ret = false;
1652         // check if anything was built
1653         TopExp_Explorer subS(shape, _subShape.ShapeType());
1654         if (ret)
1655         {
1656           for (; ret && subS.More(); subS.Next())
1657             if ( !_father->GetSubMesh( subS.Current() )->IsMeshComputed() &&
1658                  ( _subShape.ShapeType() != TopAbs_EDGE ||
1659                    !algo->isDegenerated( TopoDS::Edge( subS.Current() ))))
1660               ret = false;
1661         }
1662         // Set _computeError
1663         if (!ret && !isComputeErrorSet)
1664         {
1665           for (subS.ReInit(); subS.More(); subS.Next())
1666           {
1667             SMESH_subMesh* sm = _father->GetSubMesh( subS.Current() );
1668             if ( !sm->IsMeshComputed() )
1669             {
1670               if ( !sm->_computeError )
1671                 sm->_computeError = SMESH_ComputeError::New();
1672               if ( sm->_computeError->IsOK() )
1673                 sm->_computeError->myName = COMPERR_ALGO_FAILED;
1674               sm->_computeState = FAILED_TO_COMPUTE;
1675               sm->_computeError->myAlgo = algo;
1676             }
1677           }
1678         }
1679         if (ret && _computeError && _computeError->myName != COMPERR_WARNING )
1680         {
1681           _computeError.reset();
1682         }
1683
1684         // send event SUBMESH_COMPUTED
1685         if ( ret ) {
1686           if ( !algo->NeedDiscreteBoundary() )
1687             // send SUBMESH_COMPUTED to dependants of all sub-meshes of shape
1688             for (subS.ReInit(); subS.More(); subS.Next())
1689             {
1690               SMESH_subMesh* sm = _father->GetSubMesh( subS.Current() );
1691               SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(false,false);
1692               while ( smIt->more() ) {
1693                 sm = smIt->next();
1694                 if ( sm->GetSubShape().ShapeType() == TopAbs_VERTEX )
1695                   sm->updateDependantsState( SUBMESH_COMPUTED );
1696                 else
1697                   break;
1698               }
1699             }
1700           else
1701             updateDependantsState( SUBMESH_COMPUTED );
1702         }
1703       }
1704       break;
1705     case COMPUTE_CANCELED:               // nothing to do
1706       break;
1707     case CLEAN:
1708       cleanDependants();
1709       removeSubMeshElementsAndNodes();
1710       _computeState = NOT_READY;
1711       algo = GetAlgo();
1712       if (algo)
1713       {
1714         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1715         if (ret)
1716           _computeState = READY_TO_COMPUTE;
1717         else
1718           setAlgoState(MISSING_HYP);
1719       }
1720       break;
1721     case SUBMESH_COMPUTED:      // nothing to do
1722       break;
1723     case SUBMESH_RESTORED:
1724       // check if a mesh is already computed that may
1725       // happen after retrieval from a file
1726       ComputeStateEngine( CHECK_COMPUTE_STATE );
1727       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1728       algo = GetAlgo();
1729       if (algo) algo->SubmeshRestored( this );
1730       break;
1731     case MESH_ENTITY_REMOVED:
1732       break;
1733     case SUBMESH_LOADED:
1734       loadDependentMeshes();
1735       ComputeSubMeshStateEngine( SUBMESH_LOADED );
1736       //break;
1737     case CHECK_COMPUTE_STATE:
1738       if ( IsMeshComputed() )
1739         _computeState = COMPUTE_OK;
1740       break;
1741     default:
1742       ASSERT(0);
1743       break;
1744     }
1745     break;
1746
1747     // ----------------------------------------------------------------------
1748
1749   case COMPUTE_OK:
1750     switch (event)
1751     {
1752     case MODIF_ALGO_STATE:
1753       ComputeStateEngine( CLEAN );
1754       algo = GetAlgo();
1755       if (algo && !algo->NeedDiscreteBoundary())
1756         cleanDependsOn( algo ); // clean sub-meshes with event CLEAN
1757       break;
1758     case COMPUTE:               // nothing to do
1759       break;
1760     case COMPUTE_CANCELED:      // nothing to do
1761       break;
1762     case CLEAN:
1763       cleanDependants();  // clean sub-meshes, dependant on this one, with event CLEAN
1764       removeSubMeshElementsAndNodes();
1765       _computeState = NOT_READY;
1766       if ( _algoState == HYP_OK )
1767         _computeState = READY_TO_COMPUTE;
1768       break;
1769     case SUBMESH_COMPUTED:      // nothing to do
1770       break;
1771     case SUBMESH_RESTORED:
1772       ComputeStateEngine( CHECK_COMPUTE_STATE );
1773       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1774       algo = GetAlgo();
1775       if (algo) algo->SubmeshRestored( this );
1776       break;
1777     case MESH_ENTITY_REMOVED:
1778       updateDependantsState    ( CHECK_COMPUTE_STATE );
1779       ComputeStateEngine       ( CHECK_COMPUTE_STATE );
1780       ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
1781       break;
1782     case CHECK_COMPUTE_STATE:
1783       if ( !IsMeshComputed() ) {
1784         if (_algoState == HYP_OK)
1785           _computeState = READY_TO_COMPUTE;
1786         else
1787           _computeState = NOT_READY;
1788       }
1789       break;
1790     case SUBMESH_LOADED:
1791       // already treated event, thanks to which _computeState == COMPUTE_OK
1792       break;
1793     default:
1794       ASSERT(0);
1795       break;
1796     }
1797     break;
1798
1799     // ----------------------------------------------------------------------
1800
1801   case FAILED_TO_COMPUTE:
1802     switch (event)
1803     {
1804     case MODIF_ALGO_STATE:
1805       if ( !IsEmpty() )
1806         ComputeStateEngine( CLEAN );
1807       algo = GetAlgo();
1808       if (algo && !algo->NeedDiscreteBoundary())
1809         cleanDependsOn( algo ); // clean sub-meshes with event CLEAN
1810       if (_algoState == HYP_OK)
1811         _computeState = READY_TO_COMPUTE;
1812       else
1813         _computeState = NOT_READY;
1814       break;
1815     case COMPUTE:        // nothing to do
1816     case COMPUTE_SUBMESH:
1817       break;
1818     case COMPUTE_CANCELED:
1819       {
1820         algo = GetAlgo();
1821         algo->CancelCompute();
1822       }
1823       break;
1824     case CLEAN:
1825       cleanDependants(); // submeshes dependent on me should be cleaned as well
1826       removeSubMeshElementsAndNodes();
1827       break;
1828     case SUBMESH_COMPUTED:      // allow retry compute
1829       if (_algoState == HYP_OK)
1830         _computeState = READY_TO_COMPUTE;
1831       else
1832         _computeState = NOT_READY;
1833       break;
1834     case SUBMESH_RESTORED:
1835       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1836       break;
1837     case MESH_ENTITY_REMOVED:
1838       break;
1839     case CHECK_COMPUTE_STATE:
1840       if ( IsMeshComputed() )
1841         _computeState = COMPUTE_OK;
1842       else
1843         if (_algoState == HYP_OK)
1844           _computeState = READY_TO_COMPUTE;
1845         else
1846           _computeState = NOT_READY;
1847       break;
1848     // case SUBMESH_LOADED:
1849     //   break;
1850     default:
1851       ASSERT(0);
1852       break;
1853     }
1854     break;
1855
1856     // ----------------------------------------------------------------------
1857   default:
1858     ASSERT(0);
1859     break;
1860   }
1861
1862   notifyListenersOnEvent( event, COMPUTE_EVENT );
1863
1864   return ret;
1865 }
1866
1867
1868 //=============================================================================
1869 /*!
1870  *
1871  */
1872 //=============================================================================
1873
1874 bool SMESH_subMesh::Evaluate(MapShapeNbElems& aResMap)
1875 {
1876   _computeError.reset();
1877
1878   bool ret = true;
1879
1880   if (_subShape.ShapeType() == TopAbs_VERTEX) {
1881     vector<int> aVec(SMDSEntity_Last,0);
1882     aVec[SMDSEntity_Node] = 1;
1883     aResMap.insert(make_pair(this,aVec));
1884     return ret;
1885   }
1886
1887   //SMESH_Gen *gen = _father->GetGen();
1888   SMESH_Algo *algo = 0;
1889   SMESH_Hypothesis::Hypothesis_Status hyp_status;
1890
1891   algo = GetAlgo();
1892   if(algo && !aResMap.count(this) )
1893   {
1894     ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1895     if (!ret) return false;
1896
1897     if (_father->HasShapeToMesh() && algo->NeedDiscreteBoundary())
1898     {
1899       // check submeshes needed
1900       bool subMeshEvaluated = true;
1901       int dimToCheck = SMESH_Gen::GetShapeDim( _subShape ) - 1;
1902       SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,/*complexShapeFirst=*/true);
1903       while ( smIt->more() && subMeshEvaluated )
1904       {
1905         SMESH_subMesh* sm = smIt->next();
1906         int dim = SMESH_Gen::GetShapeDim( sm->GetSubShape() );
1907         if (dim < dimToCheck) break; // the rest subMeshes are all of less dimension
1908         const vector<int> & nbs = aResMap[ sm ];
1909         subMeshEvaluated = (std::accumulate( nbs.begin(), nbs.end(), 0 ) > 0 );
1910       }
1911       if ( !subMeshEvaluated )
1912         return false;
1913     }
1914     _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo);
1915     ret = algo->Evaluate((*_father), _subShape, aResMap);
1916
1917     aResMap.insert( make_pair( this,vector<int>(0)));
1918   }
1919
1920   return ret;
1921 }
1922
1923
1924 //=======================================================================
1925 /*!
1926  * \brief Update compute_state by _computeError and send proper events to
1927  * dependent submeshes
1928   * \retval bool - true if _computeError is NOT set
1929  */
1930 //=======================================================================
1931
1932 bool SMESH_subMesh::checkComputeError(SMESH_Algo*         theAlgo,
1933                                       const bool          theComputeOK,
1934                                       const TopoDS_Shape& theShape)
1935 {
1936   bool noErrors = true;
1937
1938   if ( !theShape.IsNull() )
1939   {
1940     // Check state of submeshes
1941     if ( !theAlgo->NeedDiscreteBoundary())
1942     {
1943       SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1944       while ( smIt->more() )
1945         if ( !smIt->next()->checkComputeError( theAlgo, theComputeOK ))
1946           noErrors = false;
1947     }
1948
1949     // Check state of neighbours
1950     if ( !theAlgo->OnlyUnaryInput() &&
1951          theShape.ShapeType() == TopAbs_COMPOUND &&
1952          !theShape.IsSame( _subShape ))
1953     {
1954       for (TopoDS_Iterator subIt( theShape ); subIt.More(); subIt.Next()) {
1955         SMESH_subMesh* sm = _father->GetSubMesh( subIt.Value() );
1956         if ( sm != this ) {
1957           if ( !sm->checkComputeError( theAlgo, theComputeOK, sm->GetSubShape() ))
1958             noErrors = false;
1959           updateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
1960         }
1961       }
1962     }
1963   }
1964   {
1965
1966     // Set my _computeState
1967
1968     if ( !_computeError || _computeError->IsOK() )
1969     {
1970       // no error description is set to this sub-mesh, check if any mesh is computed
1971       _computeState = IsMeshComputed() ? COMPUTE_OK : FAILED_TO_COMPUTE;
1972       if ( _computeState != COMPUTE_OK )
1973       {
1974         if ( _subShape.ShapeType() == TopAbs_EDGE &&
1975              SMESH_Algo::isDegenerated( TopoDS::Edge( _subShape )) )
1976           _computeState = COMPUTE_OK;
1977         else if ( theComputeOK )
1978           _computeError = SMESH_ComputeError::New(COMPERR_NO_MESH_ON_SHAPE,"",theAlgo);
1979       }
1980     }
1981
1982     if ( _computeError && !_computeError->IsOK() )
1983     {
1984       if ( !_computeError->myAlgo )
1985         _computeError->myAlgo = theAlgo;
1986
1987       // Show error
1988       SMESH_Comment text;
1989       text << theAlgo->GetName() << " failed on sub-shape #" << _Id << " with error ";
1990       if (_computeError->IsCommon() )
1991         text << _computeError->CommonName();
1992       else
1993         text << _computeError->myName;
1994       if ( _computeError->myComment.size() > 0 )
1995         text << " \"" << _computeError->myComment << "\"";
1996
1997       INFOS( text );
1998
1999       _computeState = _computeError->IsKO() ? FAILED_TO_COMPUTE : COMPUTE_OK;
2000
2001       noErrors = false;
2002     }
2003   }
2004   return noErrors;
2005 }
2006
2007 //=======================================================================
2008 //function : updateSubMeshState
2009 //purpose  :
2010 //=======================================================================
2011
2012 void SMESH_subMesh::updateSubMeshState(const compute_state theState)
2013 {
2014   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
2015   while ( smIt->more() )
2016     smIt->next()->_computeState = theState;
2017 }
2018
2019 //=======================================================================
2020 //function : ComputeSubMeshStateEngine
2021 //purpose  :
2022 //=======================================================================
2023
2024 void SMESH_subMesh::ComputeSubMeshStateEngine(int event, const bool includeSelf)
2025 {
2026   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(includeSelf,false);
2027   while ( smIt->more() )
2028     smIt->next()->ComputeStateEngine(event);
2029 }
2030
2031 //=======================================================================
2032 //function : updateDependantsState
2033 //purpose  :
2034 //=======================================================================
2035
2036 void SMESH_subMesh::updateDependantsState(const compute_event theEvent)
2037 {
2038   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
2039   for (; it.More(); it.Next())
2040   {
2041     const TopoDS_Shape& ancestor = it.Value();
2042     if ( SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor))
2043       aSubMesh->ComputeStateEngine( theEvent );
2044   }
2045 }
2046
2047 //=============================================================================
2048 /*!
2049  *
2050  */
2051 //=============================================================================
2052
2053 void SMESH_subMesh::cleanDependants()
2054 {
2055   int dimToClean = SMESH_Gen::GetShapeDim( _subShape ) + 1;
2056
2057   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
2058   for (; it.More(); it.Next())
2059   {
2060     const TopoDS_Shape& ancestor = it.Value();
2061     if ( SMESH_Gen::GetShapeDim( ancestor ) == dimToClean ) {
2062       // PAL8021. do not go upper than SOLID, else ComputeStateEngine(CLEAN)
2063       // will erase mesh on other shapes in a compound
2064       if ( ancestor.ShapeType() >= TopAbs_SOLID ) {
2065         SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor);
2066         if (aSubMesh &&
2067             !aSubMesh->IsEmpty() ) // prevent infinite CLEAN via event lesteners
2068           aSubMesh->ComputeStateEngine(CLEAN);
2069       }
2070     }
2071   }
2072 }
2073
2074 //=============================================================================
2075 /*!
2076  *
2077  */
2078 //=============================================================================
2079
2080 void SMESH_subMesh::removeSubMeshElementsAndNodes()
2081 {
2082   cleanSubMesh( this );
2083
2084   // algo may bind a submesh not to _subShape, eg 3D algo
2085   // sets nodes on SHELL while _subShape may be SOLID
2086
2087   int dim = SMESH_Gen::GetShapeDim( _subShape );
2088   int type = _subShape.ShapeType() + 1;
2089   for ( ; type <= TopAbs_EDGE; type++) {
2090     if ( dim == SMESH_Gen::GetShapeDim( (TopAbs_ShapeEnum) type ))
2091     {
2092       TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type );
2093       for ( ; exp.More(); exp.Next() )
2094         cleanSubMesh( _father->GetSubMeshContaining( exp.Current() ));
2095     }
2096     else
2097       break;
2098   }
2099 }
2100
2101 //=======================================================================
2102 //function : getCollection
2103 //purpose  : return a shape containing all sub-shapes of the MainShape that can be
2104 //           meshed at once along with _subShape
2105 //=======================================================================
2106
2107 TopoDS_Shape SMESH_subMesh::getCollection(SMESH_Gen * theGen,
2108                                           SMESH_Algo* theAlgo,
2109                                           bool &      theSubComputed,
2110                                           bool &      theSubFailed,
2111                                           std::vector<SMESH_subMesh*>& theSubs)
2112 {
2113   theSubComputed = SubMeshesComputed( & theSubFailed );
2114
2115   TopoDS_Shape mainShape = _father->GetMeshDS()->ShapeToMesh();
2116
2117   if ( mainShape.IsSame( _subShape ))
2118     return _subShape;
2119
2120   const bool ignoreAuxiliaryHyps = false;
2121   list<const SMESHDS_Hypothesis*> aUsedHyp =
2122     theAlgo->GetUsedHypothesis( *_father, _subShape, ignoreAuxiliaryHyps ); // copy
2123
2124   // put in a compound all shapes with the same hypothesis assigned
2125   // and a good ComputState
2126
2127   TopoDS_Compound aCompound;
2128   BRep_Builder aBuilder;
2129   aBuilder.MakeCompound( aCompound );
2130
2131   theSubs.clear();
2132
2133   TopExp_Explorer anExplorer( mainShape, _subShape.ShapeType() );
2134   for ( ; anExplorer.More(); anExplorer.Next() )
2135   {
2136     const TopoDS_Shape& S = anExplorer.Current();
2137     SMESH_subMesh* subMesh = _father->GetSubMesh( S );
2138     theSubs.push_back( subMesh );
2139     if ( subMesh == this )
2140     {
2141       aBuilder.Add( aCompound, S );
2142     }
2143     else if ( subMesh->GetComputeState() == READY_TO_COMPUTE )
2144     {
2145       SMESH_Algo* anAlgo = theGen->GetAlgo( *_father, S );
2146       if (strcmp( anAlgo->GetName(), theAlgo->GetName()) == 0 && // same algo
2147           anAlgo->GetUsedHypothesis( *_father, S, ignoreAuxiliaryHyps ) == aUsedHyp) // same hyps
2148         aBuilder.Add( aCompound, S );
2149       if ( !subMesh->SubMeshesComputed() )
2150         theSubComputed = false;
2151     }
2152   }
2153
2154   return aCompound;
2155 }
2156
2157 //=======================================================================
2158 //function : getSimilarAttached
2159 //purpose  : return a hypothesis attached to theShape.
2160 //           If theHyp is provided, similar but not same hypotheses
2161 //           is returned; else only applicable ones having theHypType
2162 //           is returned
2163 //=======================================================================
2164
2165 const SMESH_Hypothesis* SMESH_subMesh::getSimilarAttached(const TopoDS_Shape&      theShape,
2166                                                           const SMESH_Hypothesis * theHyp,
2167                                                           const int                theHypType)
2168 {
2169   SMESH_HypoFilter hypoKind;
2170   hypoKind.Init( hypoKind.HasType( theHyp ? theHyp->GetType() : theHypType ));
2171   if ( theHyp ) {
2172     hypoKind.And   ( hypoKind.HasDim( theHyp->GetDim() ));
2173     hypoKind.AndNot( hypoKind.Is( theHyp ));
2174     if ( theHyp->IsAuxiliary() )
2175       hypoKind.And( hypoKind.HasName( theHyp->GetName() ));
2176     else
2177       hypoKind.AndNot( hypoKind.IsAuxiliary());
2178   }
2179   else {
2180     hypoKind.And( hypoKind.IsApplicableTo( theShape ));
2181   }
2182
2183   return _father->GetHypothesis( theShape, hypoKind, false );
2184 }
2185
2186 //=======================================================================
2187 //function : CheckConcurentHypothesis
2188 //purpose  : check if there are several applicable hypothesis attached to
2189 //           ancestors
2190 //=======================================================================
2191
2192 SMESH_Hypothesis::Hypothesis_Status
2193   SMESH_subMesh::CheckConcurentHypothesis (const int theHypType)
2194 {
2195   MESSAGE ("SMESH_subMesh::CheckConcurentHypothesis");
2196
2197   // is there local hypothesis on me?
2198   if ( getSimilarAttached( _subShape, 0, theHypType ) )
2199     return SMESH_Hypothesis::HYP_OK;
2200
2201
2202   TopoDS_Shape aPrevWithHyp;
2203   const SMESH_Hypothesis* aPrevHyp = 0;
2204   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
2205   for (; it.More(); it.Next())
2206   {
2207     const TopoDS_Shape& ancestor = it.Value();
2208     const SMESH_Hypothesis* hyp = getSimilarAttached( ancestor, 0, theHypType );
2209     if ( hyp )
2210     {
2211       if ( aPrevWithHyp.IsNull() || aPrevWithHyp.IsSame( ancestor ))
2212       {
2213         aPrevWithHyp = ancestor;
2214         aPrevHyp     = hyp;
2215       }
2216       else if ( aPrevWithHyp.ShapeType() == ancestor.ShapeType() && aPrevHyp != hyp )
2217         return SMESH_Hypothesis::HYP_CONCURENT;
2218       else
2219         return SMESH_Hypothesis::HYP_OK;
2220     }
2221   }
2222   return SMESH_Hypothesis::HYP_OK;
2223 }
2224
2225 //================================================================================
2226 /*!
2227  * \brief Constructor of OwnListenerData
2228  */
2229 //================================================================================
2230
2231 SMESH_subMesh::OwnListenerData::OwnListenerData( SMESH_subMesh* sm, EventListener* el):
2232   mySubMesh( sm ),
2233   myMeshID( sm ? sm->GetFather()->GetId() : -1 ),
2234   mySubMeshID( sm ? sm->GetId() : -1 ),
2235   myListener( el )
2236 {
2237 }
2238
2239 //================================================================================
2240 /*!
2241  * \brief Sets an event listener and its data to a submesh
2242  * \param listener - the listener to store
2243  * \param data - the listener data to store
2244  * \param where - the submesh to store the listener and it's data
2245  * 
2246  * It remembers the submesh where it puts the listener in order to delete
2247  * them when HYP_OK algo_state is lost
2248  * After being set, event listener is notified on each event of where submesh.
2249  */
2250 //================================================================================
2251
2252 void SMESH_subMesh::SetEventListener(EventListener*     listener,
2253                                      EventListenerData* data,
2254                                      SMESH_subMesh*     where)
2255 {
2256   if ( listener && where ) {
2257     where->setEventListener( listener, data );
2258     _ownListeners.push_back( OwnListenerData( where, listener ));
2259   }
2260 }
2261
2262 //================================================================================
2263 /*!
2264  * \brief Sets an event listener and its data to a submesh
2265  * \param listener - the listener to store
2266  * \param data - the listener data to store
2267  * 
2268  * After being set, event listener is notified on each event of a submesh.
2269  */
2270 //================================================================================
2271
2272 void SMESH_subMesh::setEventListener(EventListener*     listener,
2273                                      EventListenerData* data)
2274 {
2275   map< EventListener*, EventListenerData* >::iterator l_d =
2276     _eventListeners.find( listener );
2277   if ( l_d != _eventListeners.end() ) {
2278     EventListenerData* curData = l_d->second;
2279     if ( curData && curData != data && curData->IsDeletable() )
2280       delete curData;
2281     l_d->second = data;
2282   }
2283   else
2284   {
2285     for ( l_d = _eventListeners.begin(); l_d != _eventListeners.end(); ++l_d )
2286       if ( listener->GetName() == l_d->first->GetName() )
2287       {
2288         EventListenerData* curData = l_d->second;
2289         if ( curData && curData != data && curData->IsDeletable() )
2290           delete curData;
2291         if ( l_d->first != listener && l_d->first->IsDeletable() )
2292           delete l_d->first;
2293         _eventListeners.erase( l_d );
2294         break;
2295       }
2296     _eventListeners.insert( make_pair( listener, data ));
2297   }
2298 }
2299
2300 //================================================================================
2301 /*!
2302  * \brief Return an event listener data
2303  * \param listener - the listener whose data is
2304  * \retval EventListenerData* - found data, maybe NULL
2305  */
2306 //================================================================================
2307
2308 EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener) const
2309 {
2310   map< EventListener*, EventListenerData* >::const_iterator l_d =
2311     _eventListeners.find( listener );
2312   if ( l_d != _eventListeners.end() )
2313     return l_d->second;
2314   return 0;
2315 }
2316
2317 //================================================================================
2318 /*!
2319  * \brief Return an event listener data
2320  * \param listenerName - the listener name
2321  * \retval EventListenerData* - found data, maybe NULL
2322  */
2323 //================================================================================
2324
2325 EventListenerData* SMESH_subMesh::GetEventListenerData(const string& listenerName) const
2326 {
2327   map< EventListener*, EventListenerData* >::const_iterator l_d = _eventListeners.begin();
2328   for ( ; l_d != _eventListeners.end(); ++l_d )
2329     if ( listenerName == l_d->first->GetName() )
2330       return l_d->second;
2331   return 0;
2332 }
2333
2334 //================================================================================
2335 /*!
2336  * \brief Notify stored event listeners on the occured event
2337  * \param event - algo_event or compute_event itself
2338  * \param eventType - algo_event or compute_event
2339  * \param hyp - hypothesis, if eventType is algo_event
2340  */
2341 //================================================================================
2342
2343 void SMESH_subMesh::notifyListenersOnEvent( const int         event,
2344                                             const event_type  eventType,
2345                                             SMESH_Hypothesis* hyp)
2346 {
2347   list< pair< EventListener*, EventListenerData* > > eventListeners( _eventListeners.begin(),
2348                                                                      _eventListeners.end());
2349   list< pair< EventListener*, EventListenerData* > >::iterator l_d = eventListeners.begin();
2350   for ( ; l_d != eventListeners.end(); ++l_d )
2351   {
2352     std::pair< EventListener*, EventListenerData* > li_da = *l_d;
2353     if ( !_eventListeners.count( li_da.first )) continue;
2354
2355     if ( li_da.first->myBusySM.insert( this ).second )
2356     {
2357       const bool isDeletable = li_da.first->IsDeletable();
2358
2359       li_da.first->ProcessEvent( event, eventType, this, li_da.second, hyp );
2360
2361       if ( !isDeletable || _eventListeners.count( li_da.first ))
2362         li_da.first->myBusySM.erase( this ); // a listener is hopefully not dead
2363     }
2364   }
2365 }
2366
2367 //================================================================================
2368 /*!
2369  * \brief Unregister the listener and delete listener's data
2370  * \param listener - the event listener
2371  */
2372 //================================================================================
2373
2374 void SMESH_subMesh::DeleteEventListener(EventListener* listener)
2375 {
2376   map< EventListener*, EventListenerData* >::iterator l_d =
2377     _eventListeners.find( listener );
2378   if ( l_d != _eventListeners.end() && l_d->first )
2379   {
2380     if ( l_d->second && l_d->second->IsDeletable() )
2381     {
2382       delete l_d->second;
2383     }
2384     l_d->first->myBusySM.erase( this );
2385     if ( l_d->first->IsDeletable() )
2386     {
2387       l_d->first->BeforeDelete( this, l_d->second );
2388       delete l_d->first;
2389     }
2390     _eventListeners.erase( l_d );
2391   }
2392 }
2393
2394 //================================================================================
2395 /*!
2396  * \brief Delete event listeners depending on algo of this submesh
2397  */
2398 //================================================================================
2399
2400 void SMESH_subMesh::deleteOwnListeners()
2401 {
2402   list< OwnListenerData >::iterator d;
2403   for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d )
2404   {
2405     if ( !_father->MeshExists( d->myMeshID ))
2406       continue;
2407     if ( _father->GetId() == d->myMeshID && !_father->GetSubMeshContaining( d->mySubMeshID ))
2408       continue;
2409     d->mySubMesh->DeleteEventListener( d->myListener );
2410   }
2411   _ownListeners.clear();
2412 }
2413
2414 //=======================================================================
2415 //function : loadDependentMeshes
2416 //purpose  : loads dependent meshes on SUBMESH_LOADED event
2417 //=======================================================================
2418
2419 void SMESH_subMesh::loadDependentMeshes()
2420 {
2421   list< OwnListenerData >::iterator d;
2422   for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d )
2423     if ( _father != d->mySubMesh->_father )
2424       d->mySubMesh->_father->Load();
2425
2426   // map< EventListener*, EventListenerData* >::iterator l_d = _eventListeners.begin();
2427   // for ( ; l_d != _eventListeners.end(); ++l_d )
2428   //   if ( l_d->second )
2429   //   {
2430   //     const list<SMESH_subMesh*>& smList = l_d->second->mySubMeshes;
2431   //     list<SMESH_subMesh*>::const_iterator sm = smList.begin();
2432   //     for ( ; sm != smList.end(); ++sm )
2433   //       if ( _father != (*sm)->_father )
2434   //         (*sm)->_father->Load();
2435   //   }
2436 }
2437
2438 //================================================================================
2439 /*!
2440  * \brief Do something on a certain event
2441  * \param event - algo_event or compute_event itself
2442  * \param eventType - algo_event or compute_event
2443  * \param subMesh - the submesh where the event occures
2444  * \param data - listener data stored in the subMesh
2445  * \param hyp - hypothesis, if eventType is algo_event
2446  * 
2447  * The base implementation translates CLEAN event to the subMesh
2448  * stored in listener data. Also it sends SUBMESH_COMPUTED event in case of
2449  * successful COMPUTE event.
2450  */
2451 //================================================================================
2452
2453 void SMESH_subMeshEventListener::ProcessEvent(const int          event,
2454                                               const int          eventType,
2455                                               SMESH_subMesh*     subMesh,
2456                                               EventListenerData* data,
2457                                               const SMESH_Hypothesis*  /*hyp*/)
2458 {
2459   if ( data && !data->mySubMeshes.empty() &&
2460        eventType == SMESH_subMesh::COMPUTE_EVENT)
2461   {
2462     ASSERT( data->mySubMeshes.front() != subMesh );
2463     list<SMESH_subMesh*>::iterator smIt = data->mySubMeshes.begin();
2464     list<SMESH_subMesh*>::iterator smEnd = data->mySubMeshes.end();
2465     switch ( event ) {
2466     case SMESH_subMesh::CLEAN:
2467       for ( ; smIt != smEnd; ++ smIt)
2468         (*smIt)->ComputeStateEngine( event );
2469       break;
2470     case SMESH_subMesh::COMPUTE:
2471     case SMESH_subMesh::COMPUTE_SUBMESH:
2472       if ( subMesh->GetComputeState() == SMESH_subMesh::COMPUTE_OK )
2473         for ( ; smIt != smEnd; ++ smIt)
2474           (*smIt)->ComputeStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
2475       break;
2476     default:;
2477     }
2478   }
2479 }
2480
2481 namespace {
2482
2483   //================================================================================
2484   /*!
2485    * \brief Iterator over submeshes and optionally prepended or appended one
2486    */
2487   //================================================================================
2488
2489   struct _Iterator : public SMDS_Iterator<SMESH_subMesh*>
2490   {
2491     _Iterator(SMDS_Iterator<SMESH_subMesh*>* subIt,
2492               SMESH_subMesh*                 prepend,
2493               SMESH_subMesh*                 append): myIt(subIt),myAppend(append)
2494     {
2495       myCur = prepend ? prepend : myIt->more() ? myIt->next() : append;
2496       if ( myCur == append ) append = 0;
2497     }
2498     /// Return true if and only if there are other object in this iterator
2499     virtual bool more()
2500     {
2501       return myCur;
2502     }
2503     /// Return the current object and step to the next one
2504     virtual SMESH_subMesh* next()
2505     {
2506       SMESH_subMesh* res = myCur;
2507       if ( myIt->more() ) { myCur = myIt->next(); }
2508       else                { myCur = myAppend; myAppend = 0; }
2509       return res;
2510     }
2511     /// ~
2512     ~_Iterator()
2513     { delete myIt; }
2514     ///
2515     SMESH_subMesh                 *myAppend, *myCur;
2516     SMDS_Iterator<SMESH_subMesh*> *myIt;
2517   };
2518 }
2519
2520 //================================================================================
2521 /*!
2522  * \brief  Return iterator on the submeshes this one depends on
2523   * \param includeSelf - this submesh to be returned also
2524   * \param reverse - if true, complex shape submeshes go first
2525  */
2526 //================================================================================
2527
2528 SMESH_subMeshIteratorPtr SMESH_subMesh::getDependsOnIterator(const bool includeSelf,
2529                                                              const bool reverse) const
2530 {
2531   SMESH_subMesh *me = (SMESH_subMesh*) this;
2532   SMESH_subMesh *prepend=0, *append=0;
2533   if ( includeSelf ) {
2534     if ( reverse ) prepend = me;
2535     else            append = me;
2536   }
2537   typedef map < int, SMESH_subMesh * > TMap;
2538   if ( reverse )
2539   {
2540     return SMESH_subMeshIteratorPtr
2541       ( new _Iterator( new SMDS_mapReverseIterator<TMap>( me->DependsOn() ), prepend, append ));
2542   }
2543   {
2544     return SMESH_subMeshIteratorPtr
2545       ( new _Iterator( new SMDS_mapIterator<TMap>( me->DependsOn() ), prepend, append ));
2546   }
2547 }
2548
2549 //================================================================================
2550 /*!
2551  * \brief  Find common submeshes (based on shared sub-shapes with other
2552   * \param theOther submesh to check
2553   * \param theSetOfCommon set of common submesh
2554  */
2555 //================================================================================
2556
2557 bool SMESH_subMesh::FindIntersection(const SMESH_subMesh* theOther,
2558                                      std::set<const SMESH_subMesh*>& theSetOfCommon ) const
2559 {
2560   int oldNb = theSetOfCommon.size();
2561   // check main submeshes
2562   const map <int, SMESH_subMesh*>::const_iterator otherEnd = theOther->_mapDepend.end();
2563   if ( theOther->_mapDepend.find(this->GetId()) != otherEnd )
2564     theSetOfCommon.insert( this );
2565   if ( _mapDepend.find(theOther->GetId()) != _mapDepend.end() )
2566     theSetOfCommon.insert( theOther );
2567   // check common submeshes
2568   map <int, SMESH_subMesh*>::const_iterator mapIt = _mapDepend.begin();
2569   for( ; mapIt != _mapDepend.end(); mapIt++ )
2570     if ( theOther->_mapDepend.find((*mapIt).first) != otherEnd )
2571       theSetOfCommon.insert( (*mapIt).second );
2572   return oldNb < theSetOfCommon.size();
2573 }