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