Salome HOME
-#if OCC_VERSION_LARGE > 0x06010000
[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           OCC_CATCH_SIGNALS;
1575
1576           algo->InitComputeError();
1577
1578           MemoryReserve aMemoryReserve;
1579           SMDS_Mesh::CheckMemory();
1580           Kernel_Utils::Localizer loc;
1581           if ( !_father->HasShapeToMesh() ) // no shape
1582           {
1583             SMESH_MesherHelper helper( *_father );
1584             helper.SetSubShape( shape );
1585             helper.SetElementsOnShape( true );
1586             ret = algo->Compute(*_father, &helper );
1587           }
1588           else
1589           {
1590             ret = algo->Compute((*_father), shape);
1591           }
1592           if ( !_computeError || (/* !ret && */_computeError->IsOK() ) ) // algo can set _computeError of submesh
1593             _computeError = algo->GetComputeError();
1594         }
1595         catch ( ::SMESH_ComputeError& comperr ) {
1596           cout << " SMESH_ComputeError caught" << endl;
1597           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1598           *_computeError = comperr;
1599         }
1600         catch ( std::bad_alloc& exc ) {
1601           MESSAGE("std::bad_alloc thrown inside algo->Compute()");
1602           if ( _computeError ) {
1603             _computeError->myName = COMPERR_MEMORY_PB;
1604             //_computeError->myComment = exc.what();
1605           }
1606           cleanSubMesh( this );
1607           throw exc;
1608         }
1609         catch ( Standard_OutOfMemory& exc ) {
1610           MESSAGE("Standard_OutOfMemory thrown inside algo->Compute()");
1611           if ( _computeError ) {
1612             _computeError->myName = COMPERR_MEMORY_PB;
1613             //_computeError->myComment = exc.what();
1614           }
1615           cleanSubMesh( this );
1616           throw std::bad_alloc();
1617         }
1618         catch (Standard_Failure& ex) {
1619           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1620           _computeError->myName    = COMPERR_OCC_EXCEPTION;
1621           _computeError->myComment += ex.DynamicType()->Name();
1622           if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) {
1623             _computeError->myComment += ": ";
1624             _computeError->myComment += ex.GetMessageString();
1625           }
1626         }
1627         catch ( SALOME_Exception& S_ex ) {
1628           const int skipSalomeShift = 7; /* to skip "Salome " of
1629                                             "Salome Exception" prefix returned
1630                                             by SALOME_Exception::what() */
1631           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1632           _computeError->myName    = COMPERR_SLM_EXCEPTION;
1633           _computeError->myComment = S_ex.what() + skipSalomeShift;
1634         }
1635         catch ( std::exception& exc ) {
1636           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
1637           _computeError->myName    = COMPERR_STD_EXCEPTION;
1638           _computeError->myComment = exc.what();
1639         }
1640         catch ( ... ) {
1641           if ( _computeError )
1642             _computeError->myName = COMPERR_EXCEPTION;
1643           else
1644             ret = false;
1645         }
1646         std::cout.rdbuf( coutBuffer ); // restore cout that could be redirected by algo
1647
1648         // check if an error reported on any sub-shape
1649         bool isComputeErrorSet = !checkComputeError( algo, ret, shape );
1650         if ( isComputeErrorSet )
1651           ret = false;
1652         // check if anything was built
1653         TopExp_Explorer subS(shape, _subShape.ShapeType());
1654         if (ret)
1655         {
1656           for (; ret && subS.More(); subS.Next())
1657             ret = _father->GetSubMesh( subS.Current() )->IsMeshComputed();
1658         }
1659         // Set _computeError
1660         if (!ret && !isComputeErrorSet)
1661         {
1662           for (subS.ReInit(); subS.More(); subS.Next())
1663           {
1664             SMESH_subMesh* sm = _father->GetSubMesh( subS.Current() );
1665             if ( !sm->IsMeshComputed() )
1666             {
1667               if ( !sm->_computeError )
1668                 sm->_computeError = SMESH_ComputeError::New();
1669               if ( sm->_computeError->IsOK() )
1670                 sm->_computeError->myName = COMPERR_ALGO_FAILED;
1671               sm->_computeState = FAILED_TO_COMPUTE;
1672               sm->_computeError->myAlgo = algo;
1673             }
1674           }
1675         }
1676         if (ret && _computeError && _computeError->myName != COMPERR_WARNING )
1677         {
1678           _computeError.reset();
1679         }
1680
1681         // send event SUBMESH_COMPUTED
1682         if ( ret ) {
1683           if ( !algo->NeedDiscreteBoundary() )
1684             // send SUBMESH_COMPUTED to dependants of all sub-meshes of shape
1685             for (subS.ReInit(); subS.More(); subS.Next())
1686             {
1687               SMESH_subMesh* sm = _father->GetSubMesh( subS.Current() );
1688               SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(false,false);
1689               while ( smIt->more() ) {
1690                 sm = smIt->next();
1691                 if ( sm->GetSubShape().ShapeType() == TopAbs_VERTEX )
1692                   sm->updateDependantsState( SUBMESH_COMPUTED );
1693                 else
1694                   break;
1695               }
1696             }
1697           else
1698             updateDependantsState( SUBMESH_COMPUTED );
1699         }
1700       }
1701       break;
1702     case COMPUTE_CANCELED:               // nothing to do
1703       break;
1704     case CLEAN:
1705       cleanDependants();
1706       removeSubMeshElementsAndNodes();
1707       _computeState = NOT_READY;
1708       algo = GetAlgo();
1709       if (algo)
1710       {
1711         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1712         if (ret)
1713           _computeState = READY_TO_COMPUTE;
1714         else
1715           setAlgoState(MISSING_HYP);
1716       }
1717       break;
1718     case SUBMESH_COMPUTED:      // nothing to do
1719       break;
1720     case SUBMESH_RESTORED:
1721       // check if a mesh is already computed that may
1722       // happen after retrieval from a file
1723       ComputeStateEngine( CHECK_COMPUTE_STATE );
1724       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1725       algo = GetAlgo();
1726       if (algo) algo->SubmeshRestored( this );
1727       break;
1728     case MESH_ENTITY_REMOVED:
1729       break;
1730     case SUBMESH_LOADED:
1731       loadDependentMeshes();
1732       ComputeSubMeshStateEngine( SUBMESH_LOADED );
1733       //break;
1734     case CHECK_COMPUTE_STATE:
1735       if ( IsMeshComputed() )
1736         _computeState = COMPUTE_OK;
1737       break;
1738     default:
1739       ASSERT(0);
1740       break;
1741     }
1742     break;
1743
1744     // ----------------------------------------------------------------------
1745
1746   case COMPUTE_OK:
1747     switch (event)
1748     {
1749     case MODIF_ALGO_STATE:
1750       ComputeStateEngine( CLEAN );
1751       algo = GetAlgo();
1752       if (algo && !algo->NeedDiscreteBoundary())
1753         cleanDependsOn( algo ); // clean sub-meshes with event CLEAN
1754       break;
1755     case COMPUTE:               // nothing to do
1756       break;
1757     case COMPUTE_CANCELED:      // nothing to do
1758       break;
1759     case CLEAN:
1760       cleanDependants();  // clean sub-meshes, dependant on this one, with event CLEAN
1761       removeSubMeshElementsAndNodes();
1762       _computeState = NOT_READY;
1763       if ( _algoState == HYP_OK )
1764         _computeState = READY_TO_COMPUTE;
1765       break;
1766     case SUBMESH_COMPUTED:      // nothing to do
1767       break;
1768     case SUBMESH_RESTORED:
1769       ComputeStateEngine( CHECK_COMPUTE_STATE );
1770       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1771       algo = GetAlgo();
1772       if (algo) algo->SubmeshRestored( this );
1773       break;
1774     case MESH_ENTITY_REMOVED:
1775       updateDependantsState    ( CHECK_COMPUTE_STATE );
1776       ComputeStateEngine       ( CHECK_COMPUTE_STATE );
1777       ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
1778       break;
1779     case CHECK_COMPUTE_STATE:
1780       if ( !IsMeshComputed() ) {
1781         if (_algoState == HYP_OK)
1782           _computeState = READY_TO_COMPUTE;
1783         else
1784           _computeState = NOT_READY;
1785       }
1786       break;
1787     case SUBMESH_LOADED:
1788       // already treated event, thanks to which _computeState == COMPUTE_OK
1789       break;
1790     default:
1791       ASSERT(0);
1792       break;
1793     }
1794     break;
1795
1796     // ----------------------------------------------------------------------
1797
1798   case FAILED_TO_COMPUTE:
1799     switch (event)
1800     {
1801     case MODIF_ALGO_STATE:
1802       if ( !IsEmpty() )
1803         ComputeStateEngine( CLEAN );
1804       algo = GetAlgo();
1805       if (algo && !algo->NeedDiscreteBoundary())
1806         cleanDependsOn( algo ); // clean sub-meshes with event CLEAN
1807       if (_algoState == HYP_OK)
1808         _computeState = READY_TO_COMPUTE;
1809       else
1810         _computeState = NOT_READY;
1811       break;
1812     case COMPUTE:        // nothing to do
1813     case COMPUTE_SUBMESH:
1814       break;
1815     case COMPUTE_CANCELED:
1816       {
1817         algo = GetAlgo();
1818         algo->CancelCompute();
1819       }
1820       break;
1821     case CLEAN:
1822       cleanDependants(); // submeshes dependent on me should be cleaned as well
1823       removeSubMeshElementsAndNodes();
1824       break;
1825     case SUBMESH_COMPUTED:      // allow retry compute
1826       if (_algoState == HYP_OK)
1827         _computeState = READY_TO_COMPUTE;
1828       else
1829         _computeState = NOT_READY;
1830       break;
1831     case SUBMESH_RESTORED:
1832       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
1833       break;
1834     case MESH_ENTITY_REMOVED:
1835       break;
1836     case CHECK_COMPUTE_STATE:
1837       if ( IsMeshComputed() )
1838         _computeState = COMPUTE_OK;
1839       else
1840         if (_algoState == HYP_OK)
1841           _computeState = READY_TO_COMPUTE;
1842         else
1843           _computeState = NOT_READY;
1844       break;
1845     // case SUBMESH_LOADED:
1846     //   break;
1847     default:
1848       ASSERT(0);
1849       break;
1850     }
1851     break;
1852
1853     // ----------------------------------------------------------------------
1854   default:
1855     ASSERT(0);
1856     break;
1857   }
1858
1859   notifyListenersOnEvent( event, COMPUTE_EVENT );
1860
1861   return ret;
1862 }
1863
1864
1865 //=============================================================================
1866 /*!
1867  *
1868  */
1869 //=============================================================================
1870
1871 bool SMESH_subMesh::Evaluate(MapShapeNbElems& aResMap)
1872 {
1873   _computeError.reset();
1874
1875   bool ret = true;
1876
1877   if (_subShape.ShapeType() == TopAbs_VERTEX) {
1878     vector<int> aVec(SMDSEntity_Last,0);
1879     aVec[SMDSEntity_Node] = 1;
1880     aResMap.insert(make_pair(this,aVec));
1881     return ret;
1882   }
1883
1884   //SMESH_Gen *gen = _father->GetGen();
1885   SMESH_Algo *algo = 0;
1886   SMESH_Hypothesis::Hypothesis_Status hyp_status;
1887
1888   algo = GetAlgo();
1889   if(algo && !aResMap.count(this) )
1890   {
1891     ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
1892     if (!ret) return false;
1893
1894     if (_father->HasShapeToMesh() && algo->NeedDiscreteBoundary())
1895     {
1896       // check submeshes needed
1897       bool subMeshEvaluated = true;
1898       int dimToCheck = SMESH_Gen::GetShapeDim( _subShape ) - 1;
1899       SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,/*complexShapeFirst=*/true);
1900       while ( smIt->more() && subMeshEvaluated )
1901       {
1902         SMESH_subMesh* sm = smIt->next();
1903         int dim = SMESH_Gen::GetShapeDim( sm->GetSubShape() );
1904         if (dim < dimToCheck) break; // the rest subMeshes are all of less dimension
1905         const vector<int> & nbs = aResMap[ sm ];
1906         subMeshEvaluated = (std::accumulate( nbs.begin(), nbs.end(), 0 ) > 0 );
1907       }
1908       if ( !subMeshEvaluated )
1909         return false;
1910     }
1911     _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo);
1912     ret = algo->Evaluate((*_father), _subShape, aResMap);
1913
1914     aResMap.insert( make_pair( this,vector<int>(0)));
1915   }
1916
1917   return ret;
1918 }
1919
1920
1921 //=======================================================================
1922 /*!
1923  * \brief Update compute_state by _computeError and send proper events to
1924  * dependent submeshes
1925   * \retval bool - true if _computeError is NOT set
1926  */
1927 //=======================================================================
1928
1929 bool SMESH_subMesh::checkComputeError(SMESH_Algo*         theAlgo,
1930                                       const bool          theComputeOK,
1931                                       const TopoDS_Shape& theShape)
1932 {
1933   bool noErrors = true;
1934
1935   if ( !theShape.IsNull() )
1936   {
1937     // Check state of submeshes
1938     if ( !theAlgo->NeedDiscreteBoundary())
1939     {
1940       SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
1941       while ( smIt->more() )
1942         if ( !smIt->next()->checkComputeError( theAlgo, theComputeOK ))
1943           noErrors = false;
1944     }
1945
1946     // Check state of neighbours
1947     if ( !theAlgo->OnlyUnaryInput() &&
1948          theShape.ShapeType() == TopAbs_COMPOUND &&
1949          !theShape.IsSame( _subShape ))
1950     {
1951       for (TopoDS_Iterator subIt( theShape ); subIt.More(); subIt.Next()) {
1952         SMESH_subMesh* sm = _father->GetSubMesh( subIt.Value() );
1953         if ( sm != this ) {
1954           if ( !sm->checkComputeError( theAlgo, theComputeOK, sm->GetSubShape() ))
1955             noErrors = false;
1956           updateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
1957         }
1958       }
1959     }
1960   }
1961   {
1962
1963     // Set my _computeState
1964
1965     if ( !_computeError || _computeError->IsOK() )
1966     {
1967       // no error description is set to this sub-mesh, check if any mesh is computed
1968       _computeState = IsMeshComputed() ? COMPUTE_OK : FAILED_TO_COMPUTE;
1969       if ( _computeState != COMPUTE_OK )
1970       {
1971         if ( _subShape.ShapeType() == TopAbs_EDGE &&
1972              SMESH_Algo::isDegenerated( TopoDS::Edge( _subShape )) )
1973           _computeState = COMPUTE_OK;
1974         else if ( theComputeOK )
1975           _computeError = SMESH_ComputeError::New(COMPERR_NO_MESH_ON_SHAPE,"",theAlgo);
1976       }
1977     }
1978
1979     if ( _computeError && !_computeError->IsOK() )
1980     {
1981       if ( !_computeError->myAlgo )
1982         _computeError->myAlgo = theAlgo;
1983
1984       // Show error
1985       SMESH_Comment text;
1986       text << theAlgo->GetName() << " failed on sub-shape #" << _Id << " with error ";
1987       if (_computeError->IsCommon() )
1988         text << _computeError->CommonName();
1989       else
1990         text << _computeError->myName;
1991       if ( _computeError->myComment.size() > 0 )
1992         text << " \"" << _computeError->myComment << "\"";
1993
1994       INFOS( text );
1995
1996       _computeState = _computeError->IsKO() ? FAILED_TO_COMPUTE : COMPUTE_OK;
1997
1998       noErrors = false;
1999     }
2000   }
2001   return noErrors;
2002 }
2003
2004 //=======================================================================
2005 //function : updateSubMeshState
2006 //purpose  :
2007 //=======================================================================
2008
2009 void SMESH_subMesh::updateSubMeshState(const compute_state theState)
2010 {
2011   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
2012   while ( smIt->more() )
2013     smIt->next()->_computeState = theState;
2014 }
2015
2016 //=======================================================================
2017 //function : ComputeSubMeshStateEngine
2018 //purpose  :
2019 //=======================================================================
2020
2021 void SMESH_subMesh::ComputeSubMeshStateEngine(int event, const bool includeSelf)
2022 {
2023   SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(includeSelf,false);
2024   while ( smIt->more() )
2025     smIt->next()->ComputeStateEngine(event);
2026 }
2027
2028 //=======================================================================
2029 //function : updateDependantsState
2030 //purpose  :
2031 //=======================================================================
2032
2033 void SMESH_subMesh::updateDependantsState(const compute_event theEvent)
2034 {
2035   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
2036   for (; it.More(); it.Next())
2037   {
2038     const TopoDS_Shape& ancestor = it.Value();
2039     if ( SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor))
2040       aSubMesh->ComputeStateEngine( theEvent );
2041   }
2042 }
2043
2044 //=============================================================================
2045 /*!
2046  *
2047  */
2048 //=============================================================================
2049
2050 void SMESH_subMesh::cleanDependants()
2051 {
2052   int dimToClean = SMESH_Gen::GetShapeDim( _subShape ) + 1;
2053
2054   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
2055   for (; it.More(); it.Next())
2056   {
2057     const TopoDS_Shape& ancestor = it.Value();
2058     if ( SMESH_Gen::GetShapeDim( ancestor ) == dimToClean ) {
2059       // PAL8021. do not go upper than SOLID, else ComputeStateEngine(CLEAN)
2060       // will erase mesh on other shapes in a compound
2061       if ( ancestor.ShapeType() >= TopAbs_SOLID ) {
2062         SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor);
2063         if (aSubMesh &&
2064             !aSubMesh->IsEmpty() ) // prevent infinite CLEAN via event lesteners
2065           aSubMesh->ComputeStateEngine(CLEAN);
2066       }
2067     }
2068   }
2069 }
2070
2071 //=============================================================================
2072 /*!
2073  *
2074  */
2075 //=============================================================================
2076
2077 void SMESH_subMesh::removeSubMeshElementsAndNodes()
2078 {
2079   cleanSubMesh( this );
2080
2081   // algo may bind a submesh not to _subShape, eg 3D algo
2082   // sets nodes on SHELL while _subShape may be SOLID
2083
2084   int dim = SMESH_Gen::GetShapeDim( _subShape );
2085   int type = _subShape.ShapeType() + 1;
2086   for ( ; type <= TopAbs_EDGE; type++) {
2087     if ( dim == SMESH_Gen::GetShapeDim( (TopAbs_ShapeEnum) type ))
2088     {
2089       TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type );
2090       for ( ; exp.More(); exp.Next() )
2091         cleanSubMesh( _father->GetSubMeshContaining( exp.Current() ));
2092     }
2093     else
2094       break;
2095   }
2096 }
2097
2098 //=======================================================================
2099 //function : getCollection
2100 //purpose  : return a shape containing all sub-shapes of the MainShape that can be
2101 //           meshed at once along with _subShape
2102 //=======================================================================
2103
2104 TopoDS_Shape SMESH_subMesh::getCollection(SMESH_Gen * theGen,
2105                                           SMESH_Algo* theAlgo,
2106                                           bool &      theSubComputed,
2107                                           bool &      theSubFailed,
2108                                           std::vector<SMESH_subMesh*>& theSubs)
2109 {
2110   theSubComputed = SubMeshesComputed( & theSubFailed );
2111
2112   TopoDS_Shape mainShape = _father->GetMeshDS()->ShapeToMesh();
2113
2114   if ( mainShape.IsSame( _subShape ))
2115     return _subShape;
2116
2117   const bool ignoreAuxiliaryHyps = false;
2118   list<const SMESHDS_Hypothesis*> aUsedHyp =
2119     theAlgo->GetUsedHypothesis( *_father, _subShape, ignoreAuxiliaryHyps ); // copy
2120
2121   // put in a compound all shapes with the same hypothesis assigned
2122   // and a good ComputState
2123
2124   TopoDS_Compound aCompound;
2125   BRep_Builder aBuilder;
2126   aBuilder.MakeCompound( aCompound );
2127
2128   theSubs.clear();
2129
2130   TopExp_Explorer anExplorer( mainShape, _subShape.ShapeType() );
2131   for ( ; anExplorer.More(); anExplorer.Next() )
2132   {
2133     const TopoDS_Shape& S = anExplorer.Current();
2134     SMESH_subMesh* subMesh = _father->GetSubMesh( S );
2135     theSubs.push_back( subMesh );
2136     if ( subMesh == this )
2137     {
2138       aBuilder.Add( aCompound, S );
2139     }
2140     else if ( subMesh->GetComputeState() == READY_TO_COMPUTE )
2141     {
2142       SMESH_Algo* anAlgo = theGen->GetAlgo( *_father, S );
2143       if (strcmp( anAlgo->GetName(), theAlgo->GetName()) == 0 && // same algo
2144           anAlgo->GetUsedHypothesis( *_father, S, ignoreAuxiliaryHyps ) == aUsedHyp) // same hyps
2145         aBuilder.Add( aCompound, S );
2146       if ( !subMesh->SubMeshesComputed() )
2147         theSubComputed = false;
2148     }
2149   }
2150
2151   return aCompound;
2152 }
2153
2154 //=======================================================================
2155 //function : getSimilarAttached
2156 //purpose  : return a hypothesis attached to theShape.
2157 //           If theHyp is provided, similar but not same hypotheses
2158 //           is returned; else only applicable ones having theHypType
2159 //           is returned
2160 //=======================================================================
2161
2162 const SMESH_Hypothesis* SMESH_subMesh::getSimilarAttached(const TopoDS_Shape&      theShape,
2163                                                           const SMESH_Hypothesis * theHyp,
2164                                                           const int                theHypType)
2165 {
2166   SMESH_HypoFilter hypoKind;
2167   hypoKind.Init( hypoKind.HasType( theHyp ? theHyp->GetType() : theHypType ));
2168   if ( theHyp ) {
2169     hypoKind.And   ( hypoKind.HasDim( theHyp->GetDim() ));
2170     hypoKind.AndNot( hypoKind.Is( theHyp ));
2171     if ( theHyp->IsAuxiliary() )
2172       hypoKind.And( hypoKind.HasName( theHyp->GetName() ));
2173     else
2174       hypoKind.AndNot( hypoKind.IsAuxiliary());
2175   }
2176   else {
2177     hypoKind.And( hypoKind.IsApplicableTo( theShape ));
2178   }
2179
2180   return _father->GetHypothesis( theShape, hypoKind, false );
2181 }
2182
2183 //=======================================================================
2184 //function : CheckConcurentHypothesis
2185 //purpose  : check if there are several applicable hypothesis attached to
2186 //           ancestors
2187 //=======================================================================
2188
2189 SMESH_Hypothesis::Hypothesis_Status
2190   SMESH_subMesh::CheckConcurentHypothesis (const int theHypType)
2191 {
2192   MESSAGE ("SMESH_subMesh::CheckConcurentHypothesis");
2193
2194   // is there local hypothesis on me?
2195   if ( getSimilarAttached( _subShape, 0, theHypType ) )
2196     return SMESH_Hypothesis::HYP_OK;
2197
2198
2199   TopoDS_Shape aPrevWithHyp;
2200   const SMESH_Hypothesis* aPrevHyp = 0;
2201   TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
2202   for (; it.More(); it.Next())
2203   {
2204     const TopoDS_Shape& ancestor = it.Value();
2205     const SMESH_Hypothesis* hyp = getSimilarAttached( ancestor, 0, theHypType );
2206     if ( hyp )
2207     {
2208       if ( aPrevWithHyp.IsNull() || aPrevWithHyp.IsSame( ancestor ))
2209       {
2210         aPrevWithHyp = ancestor;
2211         aPrevHyp     = hyp;
2212       }
2213       else if ( aPrevWithHyp.ShapeType() == ancestor.ShapeType() && aPrevHyp != hyp )
2214         return SMESH_Hypothesis::HYP_CONCURENT;
2215       else
2216         return SMESH_Hypothesis::HYP_OK;
2217     }
2218   }
2219   return SMESH_Hypothesis::HYP_OK;
2220 }
2221
2222 //================================================================================
2223 /*!
2224  * \brief Constructor of OwnListenerData
2225  */
2226 //================================================================================
2227
2228 SMESH_subMesh::OwnListenerData::OwnListenerData( SMESH_subMesh* sm, EventListener* el):
2229   mySubMesh( sm ),
2230   myMeshID( sm ? sm->GetFather()->GetId() : -1 ),
2231   mySubMeshID( sm ? sm->GetId() : -1 ),
2232   myListener( el )
2233 {
2234 }
2235
2236 //================================================================================
2237 /*!
2238  * \brief Sets an event listener and its data to a submesh
2239  * \param listener - the listener to store
2240  * \param data - the listener data to store
2241  * \param where - the submesh to store the listener and it's data
2242  * 
2243  * It remembers the submesh where it puts the listener in order to delete
2244  * them when HYP_OK algo_state is lost
2245  * After being set, event listener is notified on each event of where submesh.
2246  */
2247 //================================================================================
2248
2249 void SMESH_subMesh::SetEventListener(EventListener*     listener,
2250                                      EventListenerData* data,
2251                                      SMESH_subMesh*     where)
2252 {
2253   if ( listener && where ) {
2254     where->setEventListener( listener, data );
2255     _ownListeners.push_back( OwnListenerData( where, listener ));
2256   }
2257 }
2258
2259 //================================================================================
2260 /*!
2261  * \brief Sets an event listener and its data to a submesh
2262  * \param listener - the listener to store
2263  * \param data - the listener data to store
2264  * 
2265  * After being set, event listener is notified on each event of a submesh.
2266  */
2267 //================================================================================
2268
2269 void SMESH_subMesh::setEventListener(EventListener*     listener,
2270                                      EventListenerData* data)
2271 {
2272   map< EventListener*, EventListenerData* >::iterator l_d =
2273     _eventListeners.find( listener );
2274   if ( l_d != _eventListeners.end() ) {
2275     EventListenerData* curData = l_d->second;
2276     if ( curData && curData != data && curData->IsDeletable() )
2277       delete curData;
2278     l_d->second = data;
2279   }
2280   else
2281   {
2282     for ( l_d = _eventListeners.begin(); l_d != _eventListeners.end(); ++l_d )
2283       if ( listener->GetName() == l_d->first->GetName() )
2284       {
2285         EventListenerData* curData = l_d->second;
2286         if ( curData && curData != data && curData->IsDeletable() )
2287           delete curData;
2288         if ( l_d->first->IsDeletable() )
2289           delete l_d->first;
2290         _eventListeners.erase( l_d );
2291         break;
2292       }
2293     _eventListeners.insert( make_pair( listener, data ));
2294   }
2295 }
2296
2297 //================================================================================
2298 /*!
2299  * \brief Return an event listener data
2300  * \param listener - the listener whose data is
2301  * \retval EventListenerData* - found data, maybe NULL
2302  */
2303 //================================================================================
2304
2305 EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener) const
2306 {
2307   map< EventListener*, EventListenerData* >::const_iterator l_d =
2308     _eventListeners.find( listener );
2309   if ( l_d != _eventListeners.end() )
2310     return l_d->second;
2311   return 0;
2312 }
2313
2314 //================================================================================
2315 /*!
2316  * \brief Return an event listener data
2317  * \param listenerName - the listener name
2318  * \retval EventListenerData* - found data, maybe NULL
2319  */
2320 //================================================================================
2321
2322 EventListenerData* SMESH_subMesh::GetEventListenerData(const string& listenerName) const
2323 {
2324   map< EventListener*, EventListenerData* >::const_iterator l_d = _eventListeners.begin();
2325   for ( ; l_d != _eventListeners.end(); ++l_d )
2326     if ( listenerName == l_d->first->GetName() )
2327       return l_d->second;
2328   return 0;
2329 }
2330
2331 //================================================================================
2332 /*!
2333  * \brief Notify stored event listeners on the occured event
2334  * \param event - algo_event or compute_event itself
2335  * \param eventType - algo_event or compute_event
2336  * \param hyp - hypothesis, if eventType is algo_event
2337  */
2338 //================================================================================
2339
2340 void SMESH_subMesh::notifyListenersOnEvent( const int         event,
2341                                             const event_type  eventType,
2342                                             SMESH_Hypothesis* hyp)
2343 {
2344   list< pair< EventListener*, EventListenerData* > > eventListeners( _eventListeners.begin(),
2345                                                                      _eventListeners.end());
2346   list< pair< EventListener*, EventListenerData* > >::iterator l_d = eventListeners.begin();
2347   for ( ; l_d != eventListeners.end(); ++l_d )
2348   {
2349     std::pair< EventListener*, EventListenerData* > li_da = *l_d;
2350     if ( !_eventListeners.count( li_da.first )) continue;
2351
2352     if ( li_da.first->myBusySM.insert( this ).second )
2353     {
2354       const bool isDeletable = li_da.first->IsDeletable();
2355
2356       li_da.first->ProcessEvent( event, eventType, this, li_da.second, hyp );
2357
2358       if ( !isDeletable || _eventListeners.count( li_da.first ))
2359         li_da.first->myBusySM.erase( this ); // a listener is hopefully not dead
2360     }
2361   }
2362 }
2363
2364 //================================================================================
2365 /*!
2366  * \brief Unregister the listener and delete listener's data
2367  * \param listener - the event listener
2368  */
2369 //================================================================================
2370
2371 void SMESH_subMesh::DeleteEventListener(EventListener* listener)
2372 {
2373   map< EventListener*, EventListenerData* >::iterator l_d =
2374     _eventListeners.find( listener );
2375   if ( l_d != _eventListeners.end() && l_d->first )
2376   {
2377     if ( l_d->second && l_d->second->IsDeletable() )
2378     {
2379       delete l_d->second;
2380     }
2381     l_d->first->myBusySM.erase( this );
2382     if ( l_d->first->IsDeletable() )
2383     {
2384       l_d->first->BeforeDelete( this, l_d->second );
2385       delete l_d->first;
2386     }
2387     _eventListeners.erase( l_d );
2388   }
2389 }
2390
2391 //================================================================================
2392 /*!
2393  * \brief Delete event listeners depending on algo of this submesh
2394  */
2395 //================================================================================
2396
2397 void SMESH_subMesh::deleteOwnListeners()
2398 {
2399   list< OwnListenerData >::iterator d;
2400   for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d )
2401   {
2402     if ( !_father->MeshExists( d->myMeshID ))
2403       continue;
2404     if ( _father->GetId() == d->myMeshID && !_father->GetSubMeshContaining( d->mySubMeshID ))
2405       continue;
2406     d->mySubMesh->DeleteEventListener( d->myListener );
2407   }
2408   _ownListeners.clear();
2409 }
2410
2411 //=======================================================================
2412 //function : loadDependentMeshes
2413 //purpose  : loads dependent meshes on SUBMESH_LOADED event
2414 //=======================================================================
2415
2416 void SMESH_subMesh::loadDependentMeshes()
2417 {
2418   list< OwnListenerData >::iterator d;
2419   for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d )
2420     if ( _father != d->mySubMesh->_father )
2421       d->mySubMesh->_father->Load();
2422
2423   // map< EventListener*, EventListenerData* >::iterator l_d = _eventListeners.begin();
2424   // for ( ; l_d != _eventListeners.end(); ++l_d )
2425   //   if ( l_d->second )
2426   //   {
2427   //     const list<SMESH_subMesh*>& smList = l_d->second->mySubMeshes;
2428   //     list<SMESH_subMesh*>::const_iterator sm = smList.begin();
2429   //     for ( ; sm != smList.end(); ++sm )
2430   //       if ( _father != (*sm)->_father )
2431   //         (*sm)->_father->Load();
2432   //   }
2433 }
2434
2435 //================================================================================
2436 /*!
2437  * \brief Do something on a certain event
2438  * \param event - algo_event or compute_event itself
2439  * \param eventType - algo_event or compute_event
2440  * \param subMesh - the submesh where the event occures
2441  * \param data - listener data stored in the subMesh
2442  * \param hyp - hypothesis, if eventType is algo_event
2443  * 
2444  * The base implementation translates CLEAN event to the subMesh
2445  * stored in listener data. Also it sends SUBMESH_COMPUTED event in case of
2446  * successful COMPUTE event.
2447  */
2448 //================================================================================
2449
2450 void SMESH_subMeshEventListener::ProcessEvent(const int          event,
2451                                               const int          eventType,
2452                                               SMESH_subMesh*     subMesh,
2453                                               EventListenerData* data,
2454                                               const SMESH_Hypothesis*  /*hyp*/)
2455 {
2456   if ( data && !data->mySubMeshes.empty() &&
2457        eventType == SMESH_subMesh::COMPUTE_EVENT)
2458   {
2459     ASSERT( data->mySubMeshes.front() != subMesh );
2460     list<SMESH_subMesh*>::iterator smIt = data->mySubMeshes.begin();
2461     list<SMESH_subMesh*>::iterator smEnd = data->mySubMeshes.end();
2462     switch ( event ) {
2463     case SMESH_subMesh::CLEAN:
2464       for ( ; smIt != smEnd; ++ smIt)
2465         (*smIt)->ComputeStateEngine( event );
2466       break;
2467     case SMESH_subMesh::COMPUTE:
2468     case SMESH_subMesh::COMPUTE_SUBMESH:
2469       if ( subMesh->GetComputeState() == SMESH_subMesh::COMPUTE_OK )
2470         for ( ; smIt != smEnd; ++ smIt)
2471           (*smIt)->ComputeStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
2472       break;
2473     default:;
2474     }
2475   }
2476 }
2477
2478 namespace {
2479
2480   //================================================================================
2481   /*!
2482    * \brief Iterator over submeshes and optionally prepended or appended one
2483    */
2484   //================================================================================
2485
2486   struct _Iterator : public SMDS_Iterator<SMESH_subMesh*>
2487   {
2488     _Iterator(SMDS_Iterator<SMESH_subMesh*>* subIt,
2489               SMESH_subMesh*                 prepend,
2490               SMESH_subMesh*                 append): myIt(subIt),myAppend(append)
2491     {
2492       myCur = prepend ? prepend : myIt->more() ? myIt->next() : append;
2493       if ( myCur == append ) append = 0;
2494     }
2495     /// Return true if and only if there are other object in this iterator
2496     virtual bool more()
2497     {
2498       return myCur;
2499     }
2500     /// Return the current object and step to the next one
2501     virtual SMESH_subMesh* next()
2502     {
2503       SMESH_subMesh* res = myCur;
2504       if ( myIt->more() ) { myCur = myIt->next(); }
2505       else                { myCur = myAppend; myAppend = 0; }
2506       return res;
2507     }
2508     /// ~
2509     ~_Iterator()
2510     { delete myIt; }
2511     ///
2512     SMESH_subMesh                 *myAppend, *myCur;
2513     SMDS_Iterator<SMESH_subMesh*> *myIt;
2514   };
2515 }
2516
2517 //================================================================================
2518 /*!
2519  * \brief  Return iterator on the submeshes this one depends on
2520   * \param includeSelf - this submesh to be returned also
2521   * \param reverse - if true, complex shape submeshes go first
2522  */
2523 //================================================================================
2524
2525 SMESH_subMeshIteratorPtr SMESH_subMesh::getDependsOnIterator(const bool includeSelf,
2526                                                              const bool reverse) const
2527 {
2528   SMESH_subMesh *me = (SMESH_subMesh*) this;
2529   SMESH_subMesh *prepend=0, *append=0;
2530   if ( includeSelf ) {
2531     if ( reverse ) prepend = me;
2532     else            append = me;
2533   }
2534   typedef map < int, SMESH_subMesh * > TMap;
2535   if ( reverse )
2536   {
2537     return SMESH_subMeshIteratorPtr
2538       ( new _Iterator( new SMDS_mapReverseIterator<TMap>( me->DependsOn() ), prepend, append ));
2539   }
2540   {
2541     return SMESH_subMeshIteratorPtr
2542       ( new _Iterator( new SMDS_mapIterator<TMap>( me->DependsOn() ), prepend, append ));
2543   }
2544 }
2545
2546 //================================================================================
2547 /*!
2548  * \brief  Find common submeshes (based on shared sub-shapes with other
2549   * \param theOther submesh to check
2550   * \param theSetOfCommon set of common submesh
2551  */
2552 //================================================================================
2553
2554 bool SMESH_subMesh::FindIntersection(const SMESH_subMesh* theOther,
2555                                      std::set<const SMESH_subMesh*>& theSetOfCommon ) const
2556 {
2557   int oldNb = theSetOfCommon.size();
2558   // check main submeshes
2559   const map <int, SMESH_subMesh*>::const_iterator otherEnd = theOther->_mapDepend.end();
2560   if ( theOther->_mapDepend.find(this->GetId()) != otherEnd )
2561     theSetOfCommon.insert( this );
2562   if ( _mapDepend.find(theOther->GetId()) != _mapDepend.end() )
2563     theSetOfCommon.insert( theOther );
2564   // check common submeshes
2565   map <int, SMESH_subMesh*>::const_iterator mapIt = _mapDepend.begin();
2566   for( ; mapIt != _mapDepend.end(); mapIt++ )
2567     if ( theOther->_mapDepend.find((*mapIt).first) != otherEnd )
2568       theSetOfCommon.insert( (*mapIt).second );
2569   return oldNb < theSetOfCommon.size();
2570 }