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