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