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