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