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