Salome HOME
Cleanup of parallel meshing + documentation
[modules/smesh.git] / src / SMESH / SMESH_Gen.cxx
1 // Copyright (C) 2007-2022  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 : implementation of SMESH idl descriptions
24 //  File   : SMESH_Gen.cxx
25 //  Author : Paul RASCLE, EDF
26 //  Module : SMESH
27 //
28 //#define CHRONODEF
29 //
30 #include "SMESH_Gen.hxx"
31
32 #include "SMESH_DriverMesh.hxx"
33 #include "SMDS_Mesh.hxx"
34 #include "SMDS_MeshElement.hxx"
35 #include "SMDS_MeshNode.hxx"
36 #include "SMESHDS_Document.hxx"
37 #include "SMESH_HypoFilter.hxx"
38 #include "SMESH_Mesh.hxx"
39 #include "SMESH_SequentialMesh.hxx"
40 #include "SMESH_ParallelMesh.hxx"
41 #include "SMESH_MesherHelper.hxx"
42 #include "SMESH_subMesh.hxx"
43
44 #include <utilities.h>
45 #include <Utils_ExceptHandlers.hxx>
46
47 #include <TopExp_Explorer.hxx>
48 #include <TopoDS.hxx>
49 #include <TopoDS_Iterator.hxx>
50
51 #include "memoire.h"
52 #include <functional>
53
54 #ifdef WIN32
55   #include <windows.h>
56 #endif
57
58 #include <Basics_Utils.hxx>
59
60 #ifndef WIN32
61 #include <boost/asio.hpp>
62 #endif
63
64 using namespace std;
65 #ifndef WIN32
66 #include <boost/filesystem.hpp>
67 namespace fs = boost::filesystem;
68 #endif
69
70 // Environment variable separator
71 #ifdef WIN32
72   #define env_sep ';'
73 #else
74   #define env_sep ':'
75 #endif
76
77 namespace
78 {
79   // a structure used to nullify SMESH_Gen field of SMESH_Hypothesis,
80   // which is needed for SMESH_Hypothesis not deleted before ~SMESH_Gen()
81   struct _Hyp : public SMESH_Hypothesis
82   {
83     void NullifyGen()
84     {
85       _gen = 0;
86     }
87   };
88
89   //================================================================================
90   /*!
91    * \brief Fill a map of shapes with all sub-shape of a sub-mesh
92    */
93   //================================================================================
94
95   TopTools_IndexedMapOfShape * fillAllowed( SMESH_subMesh*               sm,
96                                             const bool                   toFill,
97                                             TopTools_IndexedMapOfShape * allowedSub )
98   {
99     if ( !toFill || !allowedSub )
100     {
101       return nullptr;
102     }
103     if ( allowedSub->IsEmpty() )
104     {
105       allowedSub->ReSize( sm->DependsOn().size() + 1 );
106       allowedSub->Add( sm->GetSubShape() );
107       for ( const auto & key_sm : sm->DependsOn() )
108         allowedSub->Add( key_sm.second->GetSubShape() );
109     }
110     return allowedSub;
111   }
112 }
113
114 //=============================================================================
115 /*!
116  *  Constructor
117  */
118 //=============================================================================
119
120 SMESH_Gen::SMESH_Gen()
121 {
122   _studyContext = new StudyContextStruct;
123   _studyContext->myDocument = new SMESHDS_Document();
124   _localId = 0;
125   _hypId   = 0;
126   _segmentation = _nbSegments = 10;
127   _compute_canceled = false;
128 }
129
130 //=============================================================================
131 /*!
132  * Destructor
133  */
134 //=============================================================================
135
136 SMESH_Gen::~SMESH_Gen()
137 {
138   std::map < int, SMESH_Hypothesis * >::iterator i_hyp = _studyContext->mapHypothesis.begin();
139   for ( ; i_hyp != _studyContext->mapHypothesis.end(); ++i_hyp )
140   {
141     if ( _Hyp* h = static_cast< _Hyp*>( i_hyp->second ))
142       h->NullifyGen();
143   }
144   delete _studyContext->myDocument;
145   delete _studyContext;
146 }
147
148 //=============================================================================
149 /*!
150  * Creates a mesh in a study.
151  * if (theIsEmbeddedMode) { mesh modification commands are not logged }
152  */
153 //=============================================================================
154
155 SMESH_Mesh* SMESH_Gen::CreateMesh(bool theIsEmbeddedMode)
156 {
157   Unexpect aCatch(SalomeException);
158
159   // create a new SMESH_mesh object
160   SMESH_Mesh *aMesh = new SMESH_SequentialMesh(
161                                      _localId++,
162                                      this,
163                                      theIsEmbeddedMode,
164                                      _studyContext->myDocument);
165   _studyContext->mapMesh[_localId-1] = aMesh;
166
167   return aMesh;
168 }
169
170 //=============================================================================
171 /*!
172  * Creates a parallel mesh in a study.
173  * if (theIsEmbeddedMode) { mesh modification commands are not logged }
174  */
175 //=============================================================================
176
177 SMESH_Mesh* SMESH_Gen::CreateParallelMesh(bool theIsEmbeddedMode)
178 {
179   Unexpect aCatch(SalomeException);
180
181   // create a new SMESH_mesh object
182   SMESH_Mesh *aMesh = new SMESH_ParallelMesh(
183                                      _localId++,
184                                      this,
185                                      theIsEmbeddedMode,
186                                      _studyContext->myDocument);
187   _studyContext->mapMesh[_localId-1] = aMesh;
188
189   return aMesh;
190 }
191
192 //=============================================================================
193 /*!
194  * Algo to run the computation of all the submeshes of a mesh in sequentila
195  */
196 //=============================================================================
197
198 bool SMESH_Gen::sequentialComputeSubMeshes(
199           SMESH_Mesh & aMesh,
200           const TopoDS_Shape & aShape,
201           const ::MeshDimension       aDim,
202           TSetOfInt*                  aShapesId /*=0*/,
203           TopTools_IndexedMapOfShape* allowedSubShapes,
204           SMESH_subMesh::compute_event &computeEvent,
205           const bool includeSelf,
206           const bool complexShapeFirst,
207           const bool   aShapeOnly)
208 {
209   MESSAGE("Compute submeshes sequentialy");
210
211   bool ret = true;
212
213   SMESH_subMeshIteratorPtr smIt;
214   SMESH_subMesh *shapeSM = aMesh.GetSubMesh(aShape);
215
216   smIt = shapeSM->getDependsOnIterator(includeSelf, !complexShapeFirst);
217   while ( smIt->more() )
218   {
219     SMESH_subMesh* smToCompute = smIt->next();
220
221     // do not mesh vertices of a pseudo shape
222     const TopoDS_Shape&        shape = smToCompute->GetSubShape();
223     const TopAbs_ShapeEnum shapeType = shape.ShapeType();
224     if ( !aMesh.HasShapeToMesh() && shapeType == TopAbs_VERTEX )
225       continue;
226
227     // check for preview dimension limitations
228     if ( aShapesId && SMESH_Gen::GetShapeDim( shapeType ) > (int)aDim )
229     {
230       // clear compute state not to show previous compute errors
231       //  if preview invoked less dimension less than previous
232       smToCompute->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
233       continue;
234     }
235
236     if (smToCompute->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE)
237     {
238       if (_compute_canceled)
239         return false;
240       smToCompute->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes ));
241       setCurrentSubMesh( smToCompute );
242       smToCompute->ComputeStateEngine( computeEvent );
243       setCurrentSubMesh( nullptr );
244       smToCompute->SetAllowedSubShapes( nullptr );
245     }
246
247     // we check all the sub-meshes here and detect if any of them failed to compute
248     if (smToCompute->GetComputeState() == SMESH_subMesh::FAILED_TO_COMPUTE &&
249         ( shapeType != TopAbs_EDGE || !SMESH_Algo::isDegenerated( TopoDS::Edge( shape ))))
250       ret = false;
251     else if ( aShapesId )
252       aShapesId->insert( smToCompute->GetId() );
253   }
254   //aMesh.GetMeshDS()->Modified();
255   return ret;
256
257 };
258
259 //=============================================================================
260 /*
261  * compute of a submesh
262  * This function is passed to the thread pool
263  */
264 //=============================================================================
265 const std::function<void(SMESH_subMesh*,
266                          SMESH_subMesh::compute_event,
267                          SMESH_subMesh*,
268                          bool,
269                          TopTools_IndexedMapOfShape *,
270                          TSetOfInt*)>
271      compute_function([] (SMESH_subMesh* sm,
272                           SMESH_subMesh::compute_event event,
273                           SMESH_subMesh *shapeSM,
274                           bool aShapeOnly,
275                           TopTools_IndexedMapOfShape *allowedSubShapes,
276                           TSetOfInt*                  aShapesId) -> void
277 {
278   if (sm->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE)
279   {
280     sm->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes ));
281     //setCurrentSubMesh( sm );
282     sm->ComputeStateEngine(event);
283     //setCurrentSubMesh( nullptr );
284     sm->SetAllowedSubShapes( nullptr );
285   }
286
287   if ( aShapesId )
288     aShapesId->insert( sm->GetId() );
289
290 });
291
292
293 //=============================================================================
294 /*!
295  * Algo to run the computation of all the submeshes of a mesh in parallel
296  */
297 //=============================================================================
298
299 bool SMESH_Gen::parallelComputeSubMeshes(
300           SMESH_Mesh & aMesh,
301           const TopoDS_Shape & aShape,
302           const ::MeshDimension       aDim,
303           TSetOfInt*                  aShapesId /*=0*/,
304           TopTools_IndexedMapOfShape* allowedSubShapes,
305           SMESH_subMesh::compute_event &computeEvent,
306           const bool includeSelf,
307           const bool complexShapeFirst,
308           const bool   aShapeOnly)
309 {
310 #ifdef WIN32
311   throw SALOME_Exception("ParallelMesh is not working on Windows");
312 #else
313
314   bool ret = true;
315
316   SMESH_subMeshIteratorPtr smIt;
317   SMESH_subMesh *shapeSM = aMesh.GetSubMesh(aShape);
318
319   TopAbs_ShapeEnum previousShapeType = TopAbs_VERTEX;
320   int nbThreads = aMesh.GetNbThreads();
321   MESSAGE("Compute submeshes with threads: " << nbThreads);
322
323
324   smIt = shapeSM->getDependsOnIterator(includeSelf, !complexShapeFirst);
325   while ( smIt->more() )
326   {
327     SMESH_subMesh* smToCompute = smIt->next();
328
329     // do not mesh vertices of a pseudo shape
330     const TopoDS_Shape&        shape = smToCompute->GetSubShape();
331     const TopAbs_ShapeEnum shapeType = shape.ShapeType();
332     // Not doing in parallel 1D and 2D meshes
333     if ( !aMesh.HasShapeToMesh() && shapeType == TopAbs_VERTEX )
334       continue;
335     if(shapeType==TopAbs_FACE||shapeType==TopAbs_EDGE)
336       aMesh.SetNbThreads(0);
337     else
338       aMesh.SetNbThreads(nbThreads);
339
340
341     if (shapeType != previousShapeType) {
342       // Waiting for all threads for the previous type to end
343       aMesh.wait();
344
345       std::string file_name;
346       switch(previousShapeType){
347         case TopAbs_FACE:
348           file_name = "Mesh2D.med";
349           break;
350         case TopAbs_EDGE:
351           file_name = "Mesh1D.med";
352           break;
353         case TopAbs_VERTEX:
354           file_name = "Mesh0D.med";
355           break;
356         case TopAbs_SOLID:
357         default:
358           file_name = "";
359           break;
360       }
361       if(file_name != "")
362       {
363         fs::path mesh_file = fs::path(aMesh.GetTmpFolder()) / fs::path(file_name);
364               SMESH_DriverMesh::exportMesh(mesh_file.string(), aMesh, "MESH");
365       }
366       //Resetting threaded pool info
367       previousShapeType = shapeType;
368     }
369
370     // check for preview dimension limitations
371     if ( aShapesId && SMESH_Gen::GetShapeDim( shapeType ) > (int)aDim )
372     {
373       // clear compute state not to show previous compute errors
374       //  if preview invoked less dimension less than previous
375       smToCompute->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
376       continue;
377     }
378     boost::asio::post(*(aMesh.GetPool()), std::bind(compute_function, smToCompute, computeEvent,
379                       shapeSM, aShapeOnly, allowedSubShapes,
380                       aShapesId));
381   }
382
383   // Waiting for the thread for Solids to finish
384   aMesh.wait();
385
386   aMesh.GetMeshDS()->Modified();
387
388   return ret;
389 #endif
390 };
391
392 //=============================================================================
393 /*
394  * Compute a mesh
395  */
396 //=============================================================================
397
398 bool SMESH_Gen::Compute(SMESH_Mesh &                aMesh,
399                         const TopoDS_Shape &        aShape,
400                         const int                   aFlags /*= COMPACT_MESH*/,
401                         const ::MeshDimension       aDim /*=::MeshDim_3D*/,
402                         TSetOfInt*                  aShapesId /*=0*/,
403                         TopTools_IndexedMapOfShape* anAllowedSubShapes/*=0*/)
404 {
405   MEMOSTAT;
406
407   const bool   aShapeOnly = aFlags & SHAPE_ONLY;
408   const bool     anUpward = aFlags & UPWARD;
409   const bool aCompactMesh = aFlags & COMPACT_MESH;
410
411   bool ret = true;
412
413   SMESH_subMesh *sm, *shapeSM = aMesh.GetSubMesh(aShape);
414
415   const bool includeSelf = true;
416   const bool complexShapeFirst = true;
417   const int  globalAlgoDim = 100;
418
419   SMESH_subMeshIteratorPtr smIt;
420
421   // Fix of Issue 22150. Due to !BLSURF->OnlyUnaryInput(), BLSURF computes edges
422   // that must be computed by Projection 1D-2D while the Projection asks to compute
423   // one face only.
424   SMESH_subMesh::compute_event computeEvent =
425     aShapeOnly ? SMESH_subMesh::COMPUTE_SUBMESH : SMESH_subMesh::COMPUTE;
426   if ( !aMesh.HasShapeToMesh() )
427     computeEvent = SMESH_subMesh::COMPUTE_NOGEOM; // if several algos and no geometry
428
429   TopTools_IndexedMapOfShape *allowedSubShapes = anAllowedSubShapes, allowedSub;
430   if ( aShapeOnly && !allowedSubShapes )
431     allowedSubShapes = &allowedSub;
432
433   if ( anUpward ) // is called from the below code in this method
434   {
435     // ===============================================
436     // Mesh all the sub-shapes starting from vertices
437     // ===============================================
438     ret = aMesh.ComputeSubMeshes(
439             this,
440             aMesh, aShape, aDim,
441             aShapesId, allowedSubShapes,
442             computeEvent,
443             includeSelf,
444             complexShapeFirst,
445             aShapeOnly);
446
447     return ret;
448   }
449   else
450   {
451     // ================================================================
452     // Apply algos that do NOT require discretized boundaries
453     // ("all-dimensional") and do NOT support sub-meshes, starting from
454     // the most complex shapes and collect sub-meshes with algos that
455     // DO support sub-meshes
456     // ================================================================
457     list< SMESH_subMesh* > smWithAlgoSupportingSubmeshes[4]; // for each dim
458
459     // map to sort sm with same dim algos according to dim of
460     // the shape the algo assigned to (issue 0021217).
461     // Other issues influenced the algo applying order:
462     // 21406, 21556, 21893, 20206
463     multimap< int, SMESH_subMesh* > shDim2sm;
464     multimap< int, SMESH_subMesh* >::reverse_iterator shDim2smIt;
465     TopoDS_Shape algoShape;
466     int prevShapeDim = -1, aShapeDim;
467
468     smIt = shapeSM->getDependsOnIterator(includeSelf, complexShapeFirst);
469     while ( smIt->more() )
470     {
471       SMESH_subMesh* smToCompute = smIt->next();
472       if ( smToCompute->GetComputeState() != SMESH_subMesh::READY_TO_COMPUTE )
473         continue;
474
475       const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
476       aShapeDim = GetShapeDim( aSubShape );
477       if ( aShapeDim < 1 ) break;
478
479       // check for preview dimension limitations
480       if ( aShapesId && aShapeDim > (int)aDim )
481         continue;
482
483       SMESH_Algo* algo = GetAlgo( smToCompute, &algoShape );
484       if ( algo && !algo->NeedDiscreteBoundary() )
485       {
486         if ( algo->SupportSubmeshes() )
487         {
488           // reload sub-meshes from shDim2sm into smWithAlgoSupportingSubmeshes
489           // so that more local algos to go first
490           if ( prevShapeDim != aShapeDim )
491           {
492             prevShapeDim = aShapeDim;
493             for ( shDim2smIt = shDim2sm.rbegin(); shDim2smIt != shDim2sm.rend(); ++shDim2smIt )
494               if ( shDim2smIt->first == globalAlgoDim )
495                 smWithAlgoSupportingSubmeshes[ aShapeDim ].push_back( shDim2smIt->second );
496               else
497                 smWithAlgoSupportingSubmeshes[ aShapeDim ].push_front( shDim2smIt->second );
498             shDim2sm.clear();
499           }
500           // add smToCompute to shDim2sm map
501           if ( algoShape.IsSame( aMesh.GetShapeToMesh() ))
502           {
503             aShapeDim = globalAlgoDim; // to compute last
504           }
505           else
506           {
507             aShapeDim = GetShapeDim( algoShape );
508             if ( algoShape.ShapeType() == TopAbs_COMPOUND )
509             {
510               TopoDS_Iterator it( algoShape );
511               aShapeDim += GetShapeDim( it.Value() );
512             }
513           }
514           shDim2sm.insert( make_pair( aShapeDim, smToCompute ));
515         }
516         else // Compute w/o support of sub-meshes
517         {
518           if (_compute_canceled)
519             return false;
520           smToCompute->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes ));
521           setCurrentSubMesh( smToCompute );
522           smToCompute->ComputeStateEngine( computeEvent );
523           setCurrentSubMesh( nullptr );
524           smToCompute->SetAllowedSubShapes( nullptr );
525           if ( aShapesId )
526             aShapesId->insert( smToCompute->GetId() );
527         }
528       }
529     }
530     // reload sub-meshes from shDim2sm into smWithAlgoSupportingSubmeshes
531     for ( shDim2smIt = shDim2sm.rbegin(); shDim2smIt != shDim2sm.rend(); ++shDim2smIt )
532       if ( shDim2smIt->first == globalAlgoDim )
533         smWithAlgoSupportingSubmeshes[3].push_back( shDim2smIt->second );
534       else
535         smWithAlgoSupportingSubmeshes[0].push_front( shDim2smIt->second );
536
537     // ======================================================
538     // Apply all-dimensional algorithms supporing sub-meshes
539     // ======================================================
540
541     std::vector< SMESH_subMesh* > smVec;
542     for ( aShapeDim = 0; aShapeDim < 4; ++aShapeDim )
543       smVec.insert( smVec.end(),
544                     smWithAlgoSupportingSubmeshes[aShapeDim].begin(),
545                     smWithAlgoSupportingSubmeshes[aShapeDim].end() );
546
547     // gather sub-shapes with local uni-dimensional algos (bos #29143)
548     // ----------------------------------------------------------------
549     TopTools_MapOfShape uniDimAlgoShapes;
550     if ( !smVec.empty() )
551     {
552       ShapeToHypothesis::Iterator s2hyps( aMesh.GetMeshDS()->GetHypotheses() );
553       for ( ; s2hyps.More(); s2hyps.Next() )
554       {
555         const TopoDS_Shape& s = s2hyps.Key();
556         if ( s.IsSame( aMesh.GetShapeToMesh() ))
557           continue;
558         for ( auto & hyp : s2hyps.Value() )
559         {
560           if ( const SMESH_Algo* algo = dynamic_cast< const SMESH_Algo*>( hyp ))
561             if ( algo->NeedDiscreteBoundary() )
562             {
563               TopAbs_ShapeEnum sType;
564               switch ( algo->GetDim() ) {
565               case 3:  sType = TopAbs_SOLID; break;
566               case 2:  sType = TopAbs_FACE; break;
567               default: sType = TopAbs_EDGE; break;
568               }
569               for ( TopExp_Explorer ex( s2hyps.Key(), sType ); ex.More(); ex.Next() )
570                 uniDimAlgoShapes.Add( ex.Current() );
571             }
572         }
573       }
574     }
575
576     {
577       // ------------------------------------------------
578       // sort list of sub-meshes according to mesh order
579       // ------------------------------------------------
580       aMesh.SortByMeshOrder( smVec );
581
582       // ------------------------------------------------------------
583       // compute sub-meshes with local uni-dimensional algos under
584       // sub-meshes with all-dimensional algos
585       // ------------------------------------------------------------
586       // start from lower shapes
587       for ( size_t i = 0; i < smVec.size(); ++i )
588       {
589         sm = smVec[i];
590         if ( sm->GetComputeState() != SMESH_subMesh::READY_TO_COMPUTE)
591           continue;
592
593         const TopAbs_ShapeEnum shapeType = sm->GetSubShape().ShapeType();
594
595         if ( !uniDimAlgoShapes.IsEmpty() )
596         {
597           // get a shape the algo is assigned to
598           if ( !GetAlgo( sm, & algoShape ))
599             continue; // strange...
600
601           // look for more local algos
602           if ( SMESH_subMesh* algoSM = aMesh.GetSubMesh( algoShape ))
603             smIt = algoSM->getDependsOnIterator(!includeSelf, !complexShapeFirst);
604           else
605             smIt = sm->getDependsOnIterator(!includeSelf, !complexShapeFirst);
606
607           while ( smIt->more() )
608           {
609             SMESH_subMesh* smToCompute = smIt->next();
610
611             const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
612             const           int aShapeDim = GetShapeDim( aSubShape );
613             if ( aShapeDim < 1 || aSubShape.ShapeType() <= shapeType )
614               continue;
615             if ( !uniDimAlgoShapes.Contains( aSubShape ))
616               continue; // [bos #29143] aMesh.GetHypothesis() is too long
617
618             // check for preview dimension limitations
619             if ( aShapesId && GetShapeDim( aSubShape.ShapeType() ) > (int)aDim )
620               continue;
621
622             SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() );
623             filter
624               .And( SMESH_HypoFilter::IsApplicableTo( aSubShape ))
625               .And( SMESH_HypoFilter::IsMoreLocalThan( algoShape, aMesh ));
626
627             if ( SMESH_Algo* subAlgo = (SMESH_Algo*) aMesh.GetHypothesis( smToCompute, filter, true))
628             {
629               if ( ! subAlgo->NeedDiscreteBoundary() ) continue;
630               TopTools_IndexedMapOfShape* localAllowed = allowedSubShapes;
631               if ( localAllowed && localAllowed->IsEmpty() )
632                 localAllowed = 0; // prevent fillAllowed() with  aSubShape
633
634               SMESH_Hypothesis::Hypothesis_Status status;
635               if ( subAlgo->CheckHypothesis( aMesh, aSubShape, status ))
636                 // mesh a lower smToCompute starting from vertices
637                 Compute( aMesh, aSubShape, aFlags | SHAPE_ONLY_UPWARD, aDim, aShapesId, localAllowed );
638             }
639           }
640         }
641         // --------------------------------
642         // apply the all-dimensional algo
643         // --------------------------------
644         {
645           if (_compute_canceled)
646             return false;
647           // check for preview dimension limitations
648           if ( aShapesId && GetShapeDim( shapeType ) > (int)aDim )
649             continue;
650           sm->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes ));
651           setCurrentSubMesh( sm );
652           sm->ComputeStateEngine( computeEvent );
653
654           setCurrentSubMesh( NULL );
655           sm->SetAllowedSubShapes( nullptr );
656           if ( aShapesId )
657             aShapesId->insert( sm->GetId() );
658         }
659       }
660     }
661
662     // -----------------------------------------------
663     // mesh the rest sub-shapes starting from vertices
664     // -----------------------------------------------
665     ret = Compute( aMesh, aShape, aFlags | UPWARD, aDim, aShapesId, allowedSubShapes );
666
667   }
668
669   MEMOSTAT;
670
671   // fix quadratic mesh by bending iternal links near concave boundary
672   if ( aCompactMesh && // a final compute
673        aShape.IsSame( aMesh.GetShapeToMesh() ) &&
674        !aShapesId && // not preview
675        ret ) // everything is OK
676   {
677     SMESH_MesherHelper aHelper( aMesh );
678     if ( aHelper.IsQuadraticMesh() != SMESH_MesherHelper::LINEAR )
679     {
680       aHelper.FixQuadraticElements( shapeSM->GetComputeError() );
681     }
682   }
683
684   if ( aCompactMesh )
685   {
686     aMesh.GetMeshDS()->Modified();
687     aMesh.GetMeshDS()->CompactMesh();
688   }
689   return ret;
690 }
691
692 //=============================================================================
693 /*!
694  * Prepare Compute a mesh
695  */
696 //=============================================================================
697 void SMESH_Gen::PrepareCompute(SMESH_Mesh &          /*aMesh*/,
698                                const TopoDS_Shape &  /*aShape*/)
699 {
700   _compute_canceled = false;
701   resetCurrentSubMesh();
702 }
703
704 //=============================================================================
705 /*!
706  * Cancel Compute a mesh
707  */
708 //=============================================================================
709 void SMESH_Gen::CancelCompute(SMESH_Mesh &          /*aMesh*/,
710                               const TopoDS_Shape &  /*aShape*/)
711 {
712   _compute_canceled = true;
713   if ( const SMESH_subMesh* sm = GetCurrentSubMesh() )
714   {
715     const_cast< SMESH_subMesh* >( sm )->ComputeStateEngine( SMESH_subMesh::COMPUTE_CANCELED );
716   }
717   resetCurrentSubMesh();
718 }
719
720 //================================================================================
721 /*!
722  * \brief Returns a sub-mesh being currently computed
723  */
724 //================================================================================
725
726 const SMESH_subMesh* SMESH_Gen::GetCurrentSubMesh() const
727 {
728   return _sm_current.empty() ? 0 : _sm_current.back();
729 }
730
731 //================================================================================
732 /*!
733  * \brief Sets a sub-mesh being currently computed.
734  *
735  * An algorithm can call Compute() for a sub-shape, hence we keep a stack of sub-meshes
736  */
737 //================================================================================
738
739 void SMESH_Gen::setCurrentSubMesh(SMESH_subMesh* sm)
740 {
741   if ( sm )
742     _sm_current.push_back( sm );
743
744   else if ( !_sm_current.empty() )
745     _sm_current.pop_back();
746 }
747
748 void SMESH_Gen::resetCurrentSubMesh()
749 {
750   _sm_current.clear();
751 }
752
753 //=============================================================================
754 /*!
755  * Evaluate a mesh
756  */
757 //=============================================================================
758
759 bool SMESH_Gen::Evaluate(SMESH_Mesh &          aMesh,
760                          const TopoDS_Shape &  aShape,
761                          MapShapeNbElems&      aResMap,
762                          const bool            anUpward,
763                          TSetOfInt*            aShapesId)
764 {
765   bool ret = true;
766
767   SMESH_subMesh *sm = aMesh.GetSubMesh(aShape);
768
769   const bool includeSelf = true;
770   const bool complexShapeFirst = true;
771   SMESH_subMeshIteratorPtr smIt;
772
773   if ( anUpward ) { // is called from below code here
774     // -----------------------------------------------
775     // mesh all the sub-shapes starting from vertices
776     // -----------------------------------------------
777     smIt = sm->getDependsOnIterator(includeSelf, !complexShapeFirst);
778     while ( smIt->more() ) {
779       SMESH_subMesh* smToCompute = smIt->next();
780
781       // do not mesh vertices of a pseudo shape
782       const TopAbs_ShapeEnum shapeType = smToCompute->GetSubShape().ShapeType();
783       //if ( !aMesh.HasShapeToMesh() && shapeType == TopAbs_VERTEX )
784       //  continue;
785       if ( !aMesh.HasShapeToMesh() ) {
786         if( shapeType == TopAbs_VERTEX || shapeType == TopAbs_WIRE ||
787             shapeType == TopAbs_SHELL )
788           continue;
789       }
790
791       smToCompute->Evaluate(aResMap);
792       if( aShapesId )
793         aShapesId->insert( smToCompute->GetId() );
794     }
795     return ret;
796   }
797   else {
798     // -----------------------------------------------------------------
799     // apply algos that DO NOT require Discreteized boundaries and DO NOT
800     // support sub-meshes, starting from the most complex shapes
801     // and collect sub-meshes with algos that DO support sub-meshes
802     // -----------------------------------------------------------------
803     list< SMESH_subMesh* > smWithAlgoSupportingSubmeshes;
804     smIt = sm->getDependsOnIterator(includeSelf, complexShapeFirst);
805     while ( smIt->more() ) {
806       SMESH_subMesh* smToCompute = smIt->next();
807       const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
808       const int aShapeDim = GetShapeDim( aSubShape );
809       if ( aShapeDim < 1 ) break;
810
811       SMESH_Algo* algo = GetAlgo( smToCompute );
812       if ( algo && !algo->NeedDiscreteBoundary() ) {
813         if ( algo->SupportSubmeshes() ) {
814           smWithAlgoSupportingSubmeshes.push_front( smToCompute );
815         }
816         else {
817           smToCompute->Evaluate(aResMap);
818           if ( aShapesId )
819             aShapesId->insert( smToCompute->GetId() );
820         }
821       }
822     }
823
824     // ------------------------------------------------------------
825     // sort list of meshes according to mesh order
826     // ------------------------------------------------------------
827     std::vector< SMESH_subMesh* > smVec( smWithAlgoSupportingSubmeshes.begin(),
828                                          smWithAlgoSupportingSubmeshes.end() );
829     aMesh.SortByMeshOrder( smVec );
830
831     // ------------------------------------------------------------
832     // compute sub-meshes under shapes with algos that DO NOT require
833     // Discreteized boundaries and DO support sub-meshes
834     // ------------------------------------------------------------
835     // start from lower shapes
836     for ( size_t i = 0; i < smVec.size(); ++i )
837     {
838       sm = smVec[i];
839
840       // get a shape the algo is assigned to
841       TopoDS_Shape algoShape;
842       if ( !GetAlgo( sm, & algoShape ))
843         continue; // strange...
844
845       // look for more local algos
846       smIt = sm->getDependsOnIterator(!includeSelf, !complexShapeFirst);
847       while ( smIt->more() ) {
848         SMESH_subMesh* smToCompute = smIt->next();
849
850         const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
851         const int aShapeDim = GetShapeDim( aSubShape );
852         if ( aShapeDim < 1 ) continue;
853
854         SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() );
855         filter
856           .And( SMESH_HypoFilter::IsApplicableTo( aSubShape ))
857           .And( SMESH_HypoFilter::IsMoreLocalThan( algoShape, aMesh ));
858
859         if ( SMESH_Algo* subAlgo = (SMESH_Algo*) aMesh.GetHypothesis( smToCompute, filter, true ))
860         {
861           if ( ! subAlgo->NeedDiscreteBoundary() ) continue;
862           SMESH_Hypothesis::Hypothesis_Status status;
863           if ( subAlgo->CheckHypothesis( aMesh, aSubShape, status ))
864             // mesh a lower smToCompute starting from vertices
865             Evaluate( aMesh, aSubShape, aResMap, /*anUpward=*/true, aShapesId );
866         }
867       }
868     }
869     // ----------------------------------------------------------
870     // apply the algos that do not require Discreteized boundaries
871     // ----------------------------------------------------------
872     for ( size_t i = 0; i < smVec.size(); ++i )
873     {
874       sm = smVec[i];
875       sm->Evaluate(aResMap);
876       if ( aShapesId )
877         aShapesId->insert( sm->GetId() );
878     }
879
880     // -----------------------------------------------
881     // mesh the rest sub-shapes starting from vertices
882     // -----------------------------------------------
883     ret = Evaluate( aMesh, aShape, aResMap, /*anUpward=*/true, aShapesId );
884   }
885
886   return ret;
887 }
888
889
890 //=======================================================================
891 //function : checkConformIgnoredAlgos
892 //purpose  :
893 //=======================================================================
894
895 static bool checkConformIgnoredAlgos(SMESH_Mesh&               aMesh,
896                                      SMESH_subMesh*            aSubMesh,
897                                      const SMESH_Algo*         aGlobIgnoAlgo,
898                                      const SMESH_Algo*         aLocIgnoAlgo,
899                                      bool &                    checkConform,
900                                      set<SMESH_subMesh*>&      aCheckedMap,
901                                      list< SMESH_Gen::TAlgoStateError > & theErrors)
902 {
903   ASSERT( aSubMesh );
904   if ( aSubMesh->GetSubShape().ShapeType() == TopAbs_VERTEX)
905     return true;
906
907
908   bool ret = true;
909
910   const list<const SMESHDS_Hypothesis*>& listHyp =
911     aMesh.GetMeshDS()->GetHypothesis( aSubMesh->GetSubShape() );
912   list<const SMESHDS_Hypothesis*>::const_iterator it=listHyp.begin();
913   for ( ; it != listHyp.end(); it++)
914   {
915     const SMESHDS_Hypothesis * aHyp = *it;
916     if (aHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO)
917       continue;
918
919     const SMESH_Algo* algo = dynamic_cast<const SMESH_Algo*> (aHyp);
920     ASSERT ( algo );
921
922     if ( aLocIgnoAlgo ) // algo is hidden by a local algo of upper dim
923     {
924       theErrors.push_back( SMESH_Gen::TAlgoStateError() );
925       theErrors.back().Set( SMESH_Hypothesis::HYP_HIDDEN_ALGO, algo, false );
926       INFOS( "Local <" << algo->GetName() << "> is hidden by local <"
927             << aLocIgnoAlgo->GetName() << ">");
928     }
929     else
930     {
931       bool       isGlobal = (aMesh.IsMainShape( aSubMesh->GetSubShape() ));
932       int             dim = algo->GetDim();
933       int aMaxGlobIgnoDim = ( aGlobIgnoAlgo ? aGlobIgnoAlgo->GetDim() : -1 );
934       bool    isNeededDim = ( aGlobIgnoAlgo ? aGlobIgnoAlgo->NeedLowerHyps( dim ) : false );
935
936       if (( dim < aMaxGlobIgnoDim && !isNeededDim ) &&
937           ( isGlobal || !aGlobIgnoAlgo->SupportSubmeshes() ))
938       {
939         // algo is hidden by a global algo
940         theErrors.push_back( SMESH_Gen::TAlgoStateError() );
941         theErrors.back().Set( SMESH_Hypothesis::HYP_HIDDEN_ALGO, algo, true );
942         INFOS( ( isGlobal ? "Global" : "Local" )
943               << " <" << algo->GetName() << "> is hidden by global <"
944               << aGlobIgnoAlgo->GetName() << ">");
945       }
946       else if ( !algo->NeedDiscreteBoundary() && !isGlobal)
947       {
948         // local algo is not hidden and hides algos on sub-shapes
949         if (checkConform && !aSubMesh->IsConform( algo ))
950         {
951           ret = false;
952           checkConform = false; // no more check conformity
953           INFOS( "ERROR: Local <" << algo->GetName() <<
954                 "> would produce not conform mesh: "
955                 "<Not Conform Mesh Allowed> hypothesis is missing");
956           theErrors.push_back( SMESH_Gen::TAlgoStateError() );
957           theErrors.back().Set( SMESH_Hypothesis::HYP_NOTCONFORM, algo, false );
958         }
959
960         // sub-algos will be hidden by a local <algo> if <algo> does not support sub-meshes
961         if ( algo->SupportSubmeshes() )
962           algo = 0;
963         SMESH_subMeshIteratorPtr revItSub =
964           aSubMesh->getDependsOnIterator( /*includeSelf=*/false, /*complexShapeFirst=*/true);
965         bool checkConform2 = false;
966         while ( revItSub->more() )
967         {
968           SMESH_subMesh* sm = revItSub->next();
969           checkConformIgnoredAlgos (aMesh, sm, aGlobIgnoAlgo,
970                                     algo, checkConform2, aCheckedMap, theErrors);
971           aCheckedMap.insert( sm );
972         }
973       }
974     }
975   }
976
977   return ret;
978 }
979
980 //=======================================================================
981 //function : checkMissing
982 //purpose  : notify on missing hypothesis
983 //           Return false if algo or hipothesis is missing
984 //=======================================================================
985
986 static bool checkMissing(SMESH_Gen*                aGen,
987                          SMESH_Mesh&               aMesh,
988                          SMESH_subMesh*            aSubMesh,
989                          const int                 aTopAlgoDim,
990                          bool*                     globalChecked,
991                          const bool                checkNoAlgo,
992                          set<SMESH_subMesh*>&      aCheckedMap,
993                          list< SMESH_Gen::TAlgoStateError > & theErrors)
994 {
995   switch ( aSubMesh->GetSubShape().ShapeType() )
996   {
997   case TopAbs_EDGE:
998   case TopAbs_FACE:
999   case TopAbs_SOLID: break; // check this sub-mesh, it can be meshed
1000   default:
1001     return true; // not meshable sub-mesh
1002   }
1003   if ( aCheckedMap.count( aSubMesh ))
1004     return true;
1005
1006   int ret = true;
1007   SMESH_Algo* algo = 0;
1008
1009   switch (aSubMesh->GetAlgoState())
1010   {
1011   case SMESH_subMesh::NO_ALGO: {
1012     if (checkNoAlgo)
1013     {
1014       // should there be any algo?
1015       int shapeDim = SMESH_Gen::GetShapeDim( aSubMesh->GetSubShape() );
1016       if (aTopAlgoDim > shapeDim)
1017       {
1018         MESSAGE( "ERROR: " << shapeDim << "D algorithm is missing" );
1019         ret = false;
1020         theErrors.push_back( SMESH_Gen::TAlgoStateError() );
1021         theErrors.back().Set( SMESH_Hypothesis::HYP_MISSING, shapeDim, true );
1022       }
1023     }
1024     return ret;
1025   }
1026   case SMESH_subMesh::MISSING_HYP: {
1027     // notify if an algo missing hyp is attached to aSubMesh
1028     algo = aSubMesh->GetAlgo();
1029     ASSERT( algo );
1030     bool IsGlobalHypothesis = aGen->IsGlobalHypothesis( algo, aMesh );
1031     if (!IsGlobalHypothesis || !globalChecked[ algo->GetDim() ])
1032     {
1033       TAlgoStateErrorName errName = SMESH_Hypothesis::HYP_MISSING;
1034       SMESH_Hypothesis::Hypothesis_Status status;
1035       algo->CheckHypothesis( aMesh, aSubMesh->GetSubShape(), status );
1036       if ( status == SMESH_Hypothesis::HYP_BAD_PARAMETER ) {
1037         MESSAGE( "ERROR: hypothesis of " << (IsGlobalHypothesis ? "Global " : "Local ")
1038                  << "<" << algo->GetName() << "> has a bad parameter value");
1039         errName = status;
1040       } else if ( status == SMESH_Hypothesis::HYP_BAD_GEOMETRY ) {
1041         MESSAGE( "ERROR: " << (IsGlobalHypothesis ? "Global " : "Local ")
1042                  << "<" << algo->GetName() << "> assigned to mismatching geometry");
1043         errName = status;
1044       } else {
1045         MESSAGE( "ERROR: " << (IsGlobalHypothesis ? "Global " : "Local ")
1046                  << "<" << algo->GetName() << "> misses some hypothesis");
1047       }
1048       if (IsGlobalHypothesis)
1049         globalChecked[ algo->GetDim() ] = true;
1050       theErrors.push_back( SMESH_Gen::TAlgoStateError() );
1051       theErrors.back().Set( errName, algo, IsGlobalHypothesis );
1052     }
1053     ret = false;
1054     break;
1055   }
1056   case SMESH_subMesh::HYP_OK:
1057     algo = aSubMesh->GetAlgo();
1058     ret = true;
1059     if (!algo->NeedDiscreteBoundary())
1060     {
1061       SMESH_subMeshIteratorPtr itsub = aSubMesh->getDependsOnIterator( /*includeSelf=*/false,
1062                                                                        /*complexShapeFirst=*/false);
1063       while ( itsub->more() )
1064         aCheckedMap.insert( itsub->next() );
1065     }
1066     break;
1067   default: ASSERT(0);
1068   }
1069
1070   // do not check under algo that hides sub-algos or
1071   // re-start checking NO_ALGO state
1072   ASSERT (algo);
1073   bool isTopLocalAlgo =
1074     ( aTopAlgoDim <= algo->GetDim() && !aGen->IsGlobalHypothesis( algo, aMesh ));
1075   if (!algo->NeedDiscreteBoundary() || isTopLocalAlgo)
1076   {
1077     bool checkNoAlgo2 = ( algo->NeedDiscreteBoundary() );
1078     SMESH_subMeshIteratorPtr itsub = aSubMesh->getDependsOnIterator( /*includeSelf=*/false,
1079                                                                      /*complexShapeFirst=*/true);
1080     while ( itsub->more() )
1081     {
1082       // sub-meshes should not be checked further more
1083       SMESH_subMesh* sm = itsub->next();
1084
1085       if (isTopLocalAlgo)
1086       {
1087         //check algo on sub-meshes
1088         int aTopAlgoDim2 = algo->GetDim();
1089         if (!checkMissing (aGen, aMesh, sm, aTopAlgoDim2,
1090                            globalChecked, checkNoAlgo2, aCheckedMap, theErrors))
1091         {
1092           ret = false;
1093           if (sm->GetAlgoState() == SMESH_subMesh::NO_ALGO )
1094             checkNoAlgo2 = false;
1095         }
1096       }
1097       aCheckedMap.insert( sm );
1098     }
1099   }
1100   return ret;
1101 }
1102
1103 //=======================================================================
1104 //function : CheckAlgoState
1105 //purpose  : notify on bad state of attached algos, return false
1106 //           if Compute() would fail because of some algo bad state
1107 //=======================================================================
1108
1109 bool SMESH_Gen::CheckAlgoState(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
1110 {
1111   list< TAlgoStateError > errors;
1112   return GetAlgoState( aMesh, aShape, errors );
1113 }
1114
1115 //=======================================================================
1116 //function : GetAlgoState
1117 //purpose  : notify on bad state of attached algos, return false
1118 //           if Compute() would fail because of some algo bad state
1119 //           theErrors list contains problems description
1120 //=======================================================================
1121
1122 bool SMESH_Gen::GetAlgoState(SMESH_Mesh&               theMesh,
1123                              const TopoDS_Shape&       theShape,
1124                              list< TAlgoStateError > & theErrors)
1125 {
1126   bool ret = true;
1127   bool hasAlgo = false;
1128
1129   SMESH_subMesh*          sm = theMesh.GetSubMesh(theShape);
1130   const SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
1131   TopoDS_Shape     mainShape = meshDS->ShapeToMesh();
1132
1133   // -----------------
1134   // get global algos
1135   // -----------------
1136
1137   const SMESH_Algo* aGlobAlgoArr[] = {0,0,0,0};
1138
1139   const list<const SMESHDS_Hypothesis*>& listHyp = meshDS->GetHypothesis( mainShape );
1140   list<const SMESHDS_Hypothesis*>::const_iterator it=listHyp.begin();
1141   for ( ; it != listHyp.end(); it++)
1142   {
1143     const SMESHDS_Hypothesis * aHyp = *it;
1144     if (aHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO)
1145       continue;
1146
1147     const SMESH_Algo* algo = dynamic_cast<const SMESH_Algo*> (aHyp);
1148     ASSERT ( algo );
1149
1150     int dim = algo->GetDim();
1151     aGlobAlgoArr[ dim ] = algo;
1152
1153     hasAlgo = true;
1154   }
1155
1156   // --------------------------------------------------------
1157   // info on algos that will be ignored because of ones that
1158   // don't NeedDiscreteBoundary() attached to super-shapes,
1159   // check that a conform mesh will be produced
1160   // --------------------------------------------------------
1161
1162
1163   // find a global algo possibly hiding sub-algos
1164   int dim;
1165   const SMESH_Algo* aGlobIgnoAlgo = 0;
1166   for (dim = 3; dim > 0; dim--)
1167   {
1168     if (aGlobAlgoArr[ dim ] &&
1169         !aGlobAlgoArr[ dim ]->NeedDiscreteBoundary() /*&&
1170         !aGlobAlgoArr[ dim ]->SupportSubmeshes()*/ )
1171     {
1172       aGlobIgnoAlgo = aGlobAlgoArr[ dim ];
1173       break;
1174     }
1175   }
1176
1177   set<SMESH_subMesh*> aCheckedSubs;
1178   bool checkConform = ( !theMesh.IsNotConformAllowed() );
1179
1180   // loop on theShape and its sub-shapes
1181   SMESH_subMeshIteratorPtr revItSub = sm->getDependsOnIterator( /*includeSelf=*/true,
1182                                                                 /*complexShapeFirst=*/true);
1183   while ( revItSub->more() )
1184   {
1185     SMESH_subMesh* smToCheck = revItSub->next();
1186     if ( smToCheck->GetSubShape().ShapeType() == TopAbs_VERTEX)
1187       break;
1188
1189     if ( aCheckedSubs.insert( smToCheck ).second ) // not yet checked
1190       if (!checkConformIgnoredAlgos (theMesh, smToCheck, aGlobIgnoAlgo,
1191                                      0, checkConform, aCheckedSubs, theErrors))
1192         ret = false;
1193
1194     if ( smToCheck->GetAlgoState() != SMESH_subMesh::NO_ALGO )
1195       hasAlgo = true;
1196   }
1197
1198   // ----------------------------------------------------------------
1199   // info on missing hypothesis and find out if all needed algos are
1200   // well defined
1201   // ----------------------------------------------------------------
1202
1203   // find max dim of global algo
1204   int aTopAlgoDim = 0;
1205   for (dim = 3; dim > 0; dim--)
1206   {
1207     if (aGlobAlgoArr[ dim ])
1208     {
1209       aTopAlgoDim = dim;
1210       break;
1211     }
1212   }
1213   bool checkNoAlgo = theMesh.HasShapeToMesh() ? bool( aTopAlgoDim ) : false;
1214   bool globalChecked[] = { false, false, false, false };
1215
1216   // loop on theShape and its sub-shapes
1217   aCheckedSubs.clear();
1218   revItSub = sm->getDependsOnIterator( /*includeSelf=*/true, /*complexShapeFirst=*/true);
1219   while ( revItSub->more() )
1220   {
1221     SMESH_subMesh* smToCheck = revItSub->next();
1222     if ( smToCheck->GetSubShape().ShapeType() == TopAbs_VERTEX)
1223       break;
1224
1225     if (!checkMissing (this, theMesh, smToCheck, aTopAlgoDim,
1226                        globalChecked, checkNoAlgo, aCheckedSubs, theErrors))
1227     {
1228       ret = false;
1229       if (smToCheck->GetAlgoState() == SMESH_subMesh::NO_ALGO )
1230         checkNoAlgo = false;
1231     }
1232   }
1233
1234   if ( !hasAlgo ) {
1235     ret = false;
1236     theErrors.push_back( TAlgoStateError() );
1237     theErrors.back().Set( SMESH_Hypothesis::HYP_MISSING, theMesh.HasShapeToMesh() ? 1 : 3, true );
1238   }
1239
1240   return ret;
1241 }
1242
1243 //=======================================================================
1244 //function : IsGlobalHypothesis
1245 //purpose  : check if theAlgo is attached to the main shape
1246 //=======================================================================
1247
1248 bool SMESH_Gen::IsGlobalHypothesis(const SMESH_Hypothesis* theHyp, SMESH_Mesh& aMesh)
1249 {
1250   SMESH_HypoFilter filter( SMESH_HypoFilter::Is( theHyp ));
1251   return aMesh.GetHypothesis( aMesh.GetMeshDS()->ShapeToMesh(), filter, false );
1252 }
1253
1254 //================================================================================
1255 /*!
1256  * \brief Return paths to xml files of plugins
1257  */
1258 //================================================================================
1259
1260 std::vector< std::string > SMESH_Gen::GetPluginXMLPaths()
1261 {
1262   // Get paths to xml files of plugins
1263   vector< string > xmlPaths;
1264   string sep;
1265   if ( const char* meshersList = getenv("SMESH_MeshersList") )
1266   {
1267     string meshers = meshersList, plugin;
1268     string::size_type from = 0, pos;
1269     while ( from < meshers.size() )
1270     {
1271       // cut off plugin name
1272       pos = meshers.find( env_sep, from );
1273       if ( pos != string::npos )
1274         plugin = meshers.substr( from, pos-from );
1275       else
1276         plugin = meshers.substr( from ), pos = meshers.size();
1277       from = pos + 1;
1278
1279       // get PLUGIN_ROOT_DIR path
1280       string rootDirVar, pluginSubDir = plugin;
1281       if ( plugin == "StdMeshers" )
1282         rootDirVar = "SMESH", pluginSubDir = "smesh";
1283       else
1284         for ( pos = 0; pos < plugin.size(); ++pos )
1285           rootDirVar += toupper( plugin[pos] );
1286       rootDirVar += "_ROOT_DIR";
1287
1288       const char* rootDir = getenv( rootDirVar.c_str() );
1289       if ( !rootDir || strlen(rootDir) == 0 )
1290       {
1291         rootDirVar = plugin + "_ROOT_DIR"; // HexoticPLUGIN_ROOT_DIR
1292         rootDir = getenv( rootDirVar.c_str() );
1293         if ( !rootDir || strlen(rootDir) == 0 ) continue;
1294       }
1295
1296       // get a separator from rootDir
1297       for ( int i = strlen( rootDir )-1; i >= 0 && sep.empty(); --i )
1298         if ( rootDir[i] == '/' || rootDir[i] == '\\' )
1299         {
1300           sep = rootDir[i];
1301           break;
1302         }
1303 #ifdef WIN32
1304       if (sep.empty() ) sep = "\\";
1305 #else
1306       if (sep.empty() ) sep = "/";
1307 #endif
1308
1309       // get a path to resource file
1310       string xmlPath = rootDir;
1311       if ( xmlPath[ xmlPath.size()-1 ] != sep[0] )
1312         xmlPath += sep;
1313       xmlPath += "share" + sep + "salome" + sep + "resources" + sep;
1314       for ( pos = 0; pos < pluginSubDir.size(); ++pos )
1315         xmlPath += tolower( pluginSubDir[pos] );
1316       xmlPath += sep + plugin + ".xml";
1317       bool fileOK;
1318 #ifdef WIN32
1319 #  ifdef UNICODE
1320       const wchar_t* path = Kernel_Utils::decode_s(xmlPath);
1321       SMESHUtils::ArrayDeleter<const wchar_t> deleter( path );
1322 #  else
1323       const char* path = xmlPath.c_str();
1324 #  endif
1325       fileOK = (GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES);
1326
1327 #else
1328       fileOK = (access(xmlPath.c_str(), F_OK) == 0);
1329 #endif
1330       if ( fileOK )
1331         xmlPaths.push_back( xmlPath );
1332     }
1333   }
1334
1335   return xmlPaths;
1336 }
1337
1338 //=============================================================================
1339 /*!
1340  * Finds algo to mesh a shape. Optionally returns a shape the found algo is bound to
1341  */
1342 //=============================================================================
1343
1344 SMESH_Algo *SMESH_Gen::GetAlgo(SMESH_Mesh &         aMesh,
1345                                const TopoDS_Shape & aShape,
1346                                TopoDS_Shape*        assignedTo)
1347 {
1348   return GetAlgo( aMesh.GetSubMesh( aShape ), assignedTo );
1349 }
1350
1351 //=============================================================================
1352 /*!
1353  * Finds algo to mesh a sub-mesh. Optionally returns a shape the found algo is bound to
1354  */
1355 //=============================================================================
1356
1357 SMESH_Algo *SMESH_Gen::GetAlgo(SMESH_subMesh * aSubMesh,
1358                                TopoDS_Shape*   assignedTo)
1359 {
1360   if ( !aSubMesh ) return 0;
1361
1362   const TopoDS_Shape & aShape = aSubMesh->GetSubShape();
1363   SMESH_Mesh&          aMesh  = *aSubMesh->GetFather();
1364
1365   SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() );
1366   if ( aMesh.HasShapeToMesh() )
1367     filter.And( filter.IsApplicableTo( aShape ));
1368
1369   typedef SMESH_Algo::Features AlgoData;
1370
1371   TopoDS_Shape assignedToShape;
1372   SMESH_Algo* algo =
1373     (SMESH_Algo*) aMesh.GetHypothesis( aSubMesh, filter, true, &assignedToShape );
1374
1375   if ( algo &&
1376        aShape.ShapeType() == TopAbs_FACE &&
1377        !aShape.IsSame( assignedToShape ) &&
1378        SMESH_MesherHelper::NbAncestors( aShape, aMesh, TopAbs_SOLID ) > 1 )
1379   {
1380     // Issue 0021559. If there is another 2D algo with different types of output
1381     // elements that can be used to mesh aShape, and 3D algos on adjacent SOLIDs
1382     // have different types of input elements, we choose a most appropriate 2D algo.
1383
1384     // try to find a concurrent 2D algo
1385     filter.AndNot( filter.Is( algo ));
1386     TopoDS_Shape assignedToShape2;
1387     SMESH_Algo* algo2 =
1388       (SMESH_Algo*) aMesh.GetHypothesis( aSubMesh, filter, true, &assignedToShape2 );
1389     if ( algo2 &&                                                  // algo found
1390          !assignedToShape2.IsSame( aMesh.GetShapeToMesh() ) &&     // algo is local
1391          ( SMESH_MesherHelper::GetGroupType( assignedToShape2 ) == // algo of the same level
1392            SMESH_MesherHelper::GetGroupType( assignedToShape )) &&
1393          aMesh.IsOrderOK( aMesh.GetSubMesh( assignedToShape2 ),    // no forced order
1394                           aMesh.GetSubMesh( assignedToShape  )))
1395     {
1396       // get algos on the adjacent SOLIDs
1397       filter.Init( filter.IsAlgo() ).And( filter.HasDim( 3 ));
1398       vector< SMESH_Algo* > algos3D;
1399       PShapeIteratorPtr solidIt = SMESH_MesherHelper::GetAncestors( aShape, aMesh,
1400                                                                     TopAbs_SOLID );
1401       while ( const TopoDS_Shape* solid = solidIt->next() )
1402         if ( SMESH_Algo* algo3D = (SMESH_Algo*) aMesh.GetHypothesis( *solid, filter, true ))
1403         {
1404           algos3D.push_back( algo3D );
1405           filter.AndNot( filter.HasName( algo3D->GetName() ));
1406         }
1407       // check compatibility of algos
1408       if ( algos3D.size() > 1 )
1409       {
1410         const AlgoData& algoData    = algo->SMESH_Algo::GetFeatures();
1411         const AlgoData& algoData2   = algo2->SMESH_Algo::GetFeatures();
1412         const AlgoData& algoData3d0 = algos3D[0]->SMESH_Algo::GetFeatures();
1413         const AlgoData& algoData3d1 = algos3D[1]->SMESH_Algo::GetFeatures();
1414         if (( algoData2.IsCompatible( algoData3d0 ) &&
1415               algoData2.IsCompatible( algoData3d1 ))
1416             &&
1417             !(algoData.IsCompatible( algoData3d0 ) &&
1418               algoData.IsCompatible( algoData3d1 )))
1419           algo = algo2;
1420       }
1421     }
1422   }
1423
1424   if ( assignedTo && algo )
1425     * assignedTo = assignedToShape;
1426
1427   return algo;
1428 }
1429
1430 //=============================================================================
1431 /*!
1432  * Returns StudyContextStruct for a study
1433  */
1434 //=============================================================================
1435
1436 StudyContextStruct *SMESH_Gen::GetStudyContext()
1437 {
1438   return _studyContext;
1439 }
1440
1441 //================================================================================
1442 /*!
1443  * \brief Return shape dimension by TopAbs_ShapeEnum
1444  */
1445 //================================================================================
1446
1447 int SMESH_Gen::GetShapeDim(const TopAbs_ShapeEnum & aShapeType)
1448 {
1449   static vector<int> dim;
1450   if ( dim.empty() )
1451   {
1452     dim.resize( TopAbs_SHAPE, -1 );
1453     dim[ TopAbs_COMPOUND ]  = MeshDim_3D;
1454     dim[ TopAbs_COMPSOLID ] = MeshDim_3D;
1455     dim[ TopAbs_SOLID ]     = MeshDim_3D;
1456     dim[ TopAbs_SHELL ]     = MeshDim_2D;
1457     dim[ TopAbs_FACE  ]     = MeshDim_2D;
1458     dim[ TopAbs_WIRE ]      = MeshDim_1D;
1459     dim[ TopAbs_EDGE ]      = MeshDim_1D;
1460     dim[ TopAbs_VERTEX ]    = MeshDim_0D;
1461   }
1462   return dim[ aShapeType ];
1463 }
1464
1465 //================================================================================
1466 /*!
1467  * \brief Return shape dimension by exploding compounds
1468  */
1469 //================================================================================
1470
1471 int SMESH_Gen::GetFlatShapeDim(const TopoDS_Shape &aShape)
1472 {
1473   int aShapeDim;
1474   if ( aShape.ShapeType() == TopAbs_COMPOUND ||
1475        aShape.ShapeType() == TopAbs_COMPSOLID )
1476   {
1477     TopoDS_Iterator it( aShape );
1478     aShapeDim = GetFlatShapeDim( it.Value() );
1479   }
1480   else
1481     aShapeDim = GetShapeDim( aShape );
1482   return aShapeDim;
1483 }
1484
1485 //=============================================================================
1486 /*!
1487  * Generate a new id unique within this Gen
1488  */
1489 //=============================================================================
1490
1491 int SMESH_Gen::GetANewId()
1492 {
1493   return _hypId++;
1494 }