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