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