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