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