Salome HOME
23315: [CEA 1929] Too much memory used to display a mesh in shading and wireframe
[modules/smesh.git] / src / SMESH / SMESH_Gen.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SMESH SMESH : implementaion of SMESH idl descriptions
24 //  File   : SMESH_Gen.cxx
25 //  Author : Paul RASCLE, EDF
26 //  Module : SMESH
27 //
28
29 //#define CHRONODEF
30
31 #include "SMESH_Gen.hxx"
32
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_MesherHelper.hxx"
40 #include "SMESH_subMesh.hxx"
41
42 #include "utilities.h"
43 #include "OpUtil.hxx"
44 #include "Utils_ExceptHandlers.hxx"
45
46 #include <TopoDS_Iterator.hxx>
47 #include <TopoDS.hxx>
48
49 #include "memoire.h"
50
51 #ifdef WIN32
52   #include <windows.h>
53 #endif
54
55 using namespace std;
56
57 //#include <vtkDebugLeaks.h>
58
59
60 //=============================================================================
61 /*!
62  *  Constructor
63  */
64 //=============================================================================
65
66 SMESH_Gen::SMESH_Gen()
67 {
68   _localId = 0;
69   _hypId   = 0;
70   _segmentation = _nbSegments = 10;
71   SMDS_Mesh::_meshList.clear();
72   _compute_canceled = false;
73   //vtkDebugLeaks::SetExitError(0);
74 }
75
76 //=============================================================================
77 /*!
78  * Destructor
79  */
80 //=============================================================================
81
82 SMESH_Gen::~SMESH_Gen()
83 {
84   std::map < int, StudyContextStruct * >::iterator i_sc = _mapStudyContext.begin();
85   for ( ; i_sc != _mapStudyContext.end(); ++i_sc )
86   {
87     delete i_sc->second->myDocument;
88     delete i_sc->second;
89   }  
90 }
91
92 //=============================================================================
93 /*!
94  * Creates a mesh in a study.
95  * if (theIsEmbeddedMode) { mesh modification commands are not logged }
96  */
97 //=============================================================================
98
99 SMESH_Mesh* SMESH_Gen::CreateMesh(int theStudyId, bool theIsEmbeddedMode)
100   throw(SALOME_Exception)
101 {
102   Unexpect aCatch(SalomeException);
103
104   // Get studyContext, create it if it does'nt exist, with a SMESHDS_Document
105   StudyContextStruct *aStudyContext = GetStudyContext(theStudyId);
106
107   // create a new SMESH_mesh object
108   SMESH_Mesh *aMesh = new SMESH_Mesh(_localId++,
109                                      theStudyId,
110                                      this,
111                                      theIsEmbeddedMode,
112                                      aStudyContext->myDocument);
113   aStudyContext->mapMesh[_localId-1] = aMesh;
114
115   return aMesh;
116 }
117
118 //=============================================================================
119 /*
120  * Compute a mesh
121  */
122 //=============================================================================
123
124 bool SMESH_Gen::Compute(SMESH_Mesh &          aMesh,
125                         const TopoDS_Shape &  aShape,
126                         const int             aFlags /*= COMPACT_MESH*/,
127                         const ::MeshDimension aDim /*=::MeshDim_3D*/,
128                         TSetOfInt*            aShapesId /*=0*/)
129 {
130   MEMOSTAT;
131
132   const bool   aShapeOnly = aFlags & SHAPE_ONLY;
133   const bool     anUpward = aFlags & UPWARD;
134   const bool aCompactMesh = aFlags & COMPACT_MESH;
135
136   bool ret = true;
137
138   SMESH_subMesh *sm = aMesh.GetSubMesh(aShape);
139
140   const bool includeSelf = true;
141   const bool complexShapeFirst = true;
142   const int  globalAlgoDim = 100;
143
144   SMESH_subMeshIteratorPtr smIt;
145
146   // Fix of Issue 22150. Due to !BLSURF->OnlyUnaryInput(), BLSURF computes edges
147   // that must be computed by Projection 1D-2D while the Projection asks to compute
148   // one face only.
149   SMESH_subMesh::compute_event computeEvent =
150     aShapeOnly ? SMESH_subMesh::COMPUTE_SUBMESH : SMESH_subMesh::COMPUTE;
151
152   if ( anUpward ) // is called from the below code in this method
153   {
154     // ===============================================
155     // Mesh all the sub-shapes starting from vertices
156     // ===============================================
157
158     smIt = sm->getDependsOnIterator(includeSelf, !complexShapeFirst);
159     while ( smIt->more() )
160     {
161       SMESH_subMesh* smToCompute = smIt->next();
162
163       // do not mesh vertices of a pseudo shape
164       const TopoDS_Shape&        shape = smToCompute->GetSubShape();
165       const TopAbs_ShapeEnum shapeType = shape.ShapeType();
166       if ( !aMesh.HasShapeToMesh() && shapeType == TopAbs_VERTEX )
167         continue;
168
169       // check for preview dimension limitations
170       if ( aShapesId && GetShapeDim( shapeType ) > (int)aDim )
171       {
172         // clear compute state not to show previous compute errors
173         //  if preview invoked less dimension less than previous
174         smToCompute->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
175         continue;
176       }
177
178       if (smToCompute->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE)
179       {
180         if (_compute_canceled)
181           return false;
182         setCurrentSubMesh( smToCompute );
183         smToCompute->ComputeStateEngine( computeEvent );
184         setCurrentSubMesh( NULL );
185       }
186
187       // we check all the sub-meshes here and detect if any of them failed to compute
188       if (smToCompute->GetComputeState() == SMESH_subMesh::FAILED_TO_COMPUTE &&
189           ( shapeType != TopAbs_EDGE || !SMESH_Algo::isDegenerated( TopoDS::Edge( shape ))))
190         ret = false;
191       else if ( aShapesId )
192         aShapesId->insert( smToCompute->GetId() );
193     }
194     //aMesh.GetMeshDS()->Modified();
195     return ret;
196   }
197   else
198   {
199     // ================================================================
200     // Apply algos that do NOT require discreteized boundaries
201     // ("all-dimensional") and do NOT support sub-meshes, starting from
202     // the most complex shapes and collect sub-meshes with algos that 
203     // DO support sub-meshes
204     // ================================================================
205
206     list< SMESH_subMesh* > smWithAlgoSupportingSubmeshes[4]; // for each dim
207
208     // map to sort sm with same dim algos according to dim of
209     // the shape the algo assigned to (issue 0021217).
210     // Other issues influenced the algo applying order:
211     // 21406, 21556, 21893, 20206
212     multimap< int, SMESH_subMesh* > shDim2sm;
213     multimap< int, SMESH_subMesh* >::reverse_iterator shDim2smIt;
214     TopoDS_Shape algoShape;
215     int prevShapeDim = -1, aShapeDim;
216
217     smIt = sm->getDependsOnIterator(includeSelf, complexShapeFirst);
218     while ( smIt->more() )
219     {
220       SMESH_subMesh* smToCompute = smIt->next();
221       if ( smToCompute->GetComputeState() != SMESH_subMesh::READY_TO_COMPUTE )
222         continue;
223
224       const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
225       aShapeDim = GetShapeDim( aSubShape );
226       if ( aShapeDim < 1 ) break;
227       
228       // check for preview dimension limitations
229       if ( aShapesId && aShapeDim > (int)aDim )
230         continue;
231
232       SMESH_Algo* algo = GetAlgo( smToCompute, &algoShape );
233       if ( algo && !algo->NeedDiscreteBoundary() )
234       {
235         if ( algo->SupportSubmeshes() )
236         {
237           // reload sub-meshes from shDim2sm into smWithAlgoSupportingSubmeshes
238           // so that more local algos to go first
239           if ( prevShapeDim != aShapeDim )
240           {
241             prevShapeDim = aShapeDim;
242             for ( shDim2smIt = shDim2sm.rbegin(); shDim2smIt != shDim2sm.rend(); ++shDim2smIt )
243               if ( shDim2smIt->first == globalAlgoDim )
244                 smWithAlgoSupportingSubmeshes[ aShapeDim ].push_back( shDim2smIt->second );
245               else
246                 smWithAlgoSupportingSubmeshes[ aShapeDim ].push_front( shDim2smIt->second );
247             shDim2sm.clear();
248           }
249           // add smToCompute to shDim2sm map
250           if ( algoShape.IsSame( aMesh.GetShapeToMesh() ))
251           {
252             aShapeDim = globalAlgoDim; // to compute last
253           }
254           else
255           {
256             aShapeDim = GetShapeDim( algoShape );
257             if ( algoShape.ShapeType() == TopAbs_COMPOUND )
258             {
259               TopoDS_Iterator it( algoShape );
260               aShapeDim += GetShapeDim( it.Value() );
261             }
262           }
263           shDim2sm.insert( make_pair( aShapeDim, smToCompute ));
264         }
265         else // Compute w/o support of sub-meshes
266         {
267           if (_compute_canceled)
268             return false;
269           setCurrentSubMesh( smToCompute );
270           smToCompute->ComputeStateEngine( computeEvent );
271           setCurrentSubMesh( NULL );
272           if ( aShapesId )
273             aShapesId->insert( smToCompute->GetId() );
274         }
275       }
276     }
277     // reload sub-meshes from shDim2sm into smWithAlgoSupportingSubmeshes
278     for ( shDim2smIt = shDim2sm.rbegin(); shDim2smIt != shDim2sm.rend(); ++shDim2smIt )
279       if ( shDim2smIt->first == globalAlgoDim )
280         smWithAlgoSupportingSubmeshes[3].push_back( shDim2smIt->second );
281       else
282         smWithAlgoSupportingSubmeshes[0].push_front( shDim2smIt->second );
283
284     // ======================================================
285     // Apply all-dimensional algorithms supporing sub-meshes
286     // ======================================================
287
288     std::vector< SMESH_subMesh* > smVec;
289     for ( aShapeDim = 0; aShapeDim < 4; ++aShapeDim )
290     {
291       // ------------------------------------------------
292       // sort list of sub-meshes according to mesh order
293       // ------------------------------------------------
294       smVec.assign( smWithAlgoSupportingSubmeshes[ aShapeDim ].begin(),
295                     smWithAlgoSupportingSubmeshes[ aShapeDim ].end() );
296       aMesh.SortByMeshOrder( smVec );
297
298       // ------------------------------------------------------------
299       // compute sub-meshes with local uni-dimensional algos under
300       // sub-meshes with all-dimensional algos
301       // ------------------------------------------------------------
302       // start from lower shapes
303       for ( size_t i = 0; i < smVec.size(); ++i )
304       {
305         sm = smVec[i];
306
307         // get a shape the algo is assigned to
308         if ( !GetAlgo( sm, & algoShape ))
309           continue; // strange...
310
311         // look for more local algos
312         smIt = sm->getDependsOnIterator(!includeSelf, !complexShapeFirst);
313         while ( smIt->more() )
314         {
315           SMESH_subMesh* smToCompute = smIt->next();
316
317           const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
318           const int aShapeDim = GetShapeDim( aSubShape );
319           //if ( aSubShape.ShapeType() == TopAbs_VERTEX ) continue;
320           if ( aShapeDim < 1 ) continue;
321
322           // check for preview dimension limitations
323           if ( aShapesId && GetShapeDim( aSubShape.ShapeType() ) > (int)aDim )
324             continue;
325
326           SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() );
327           filter
328             .And( SMESH_HypoFilter::IsApplicableTo( aSubShape ))
329             .And( SMESH_HypoFilter::IsMoreLocalThan( algoShape, aMesh ));
330
331           if ( SMESH_Algo* subAlgo = (SMESH_Algo*) aMesh.GetHypothesis( smToCompute, filter, true))
332           {
333             if ( ! subAlgo->NeedDiscreteBoundary() ) continue;
334             SMESH_Hypothesis::Hypothesis_Status status;
335             if ( subAlgo->CheckHypothesis( aMesh, aSubShape, status ))
336               // mesh a lower smToCompute starting from vertices
337               Compute( aMesh, aSubShape, aFlags | SHAPE_ONLY_UPWARD, aDim, aShapesId );
338               // Compute( aMesh, aSubShape, aShapeOnly, /*anUpward=*/true, aDim, aShapesId );
339           }
340         }
341       }
342       // --------------------------------
343       // apply the all-dimensional algos
344       // --------------------------------
345       for ( size_t i = 0; i < smVec.size(); ++i )
346       {
347         sm = smVec[i];
348         if ( sm->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE)
349         {
350           const TopAbs_ShapeEnum shapeType = sm->GetSubShape().ShapeType();
351           // check for preview dimension limitations
352           if ( aShapesId && GetShapeDim( shapeType ) > (int)aDim )
353             continue;
354
355           if (_compute_canceled)
356             return false;
357           setCurrentSubMesh( sm );
358           sm->ComputeStateEngine( computeEvent );
359           setCurrentSubMesh( NULL );
360           if ( aShapesId )
361             aShapesId->insert( sm->GetId() );
362         }
363       }
364     } // loop on shape dimensions
365
366     // -----------------------------------------------
367     // mesh the rest sub-shapes starting from vertices
368     // -----------------------------------------------
369     ret = Compute( aMesh, aShape, aFlags | UPWARD, aDim, aShapesId );
370   }
371
372   MEMOSTAT;
373
374   if ( aCompactMesh )
375     aMesh.GetMeshDS()->compactMesh();
376
377   // fix quadratic mesh by bending iternal links near concave boundary
378   if ( aCompactMesh && // a final compute
379        aShape.IsSame( aMesh.GetShapeToMesh() ) &&
380        !aShapesId && // not preview
381        ret ) // everything is OK
382   {
383     SMESH_MesherHelper aHelper( aMesh );
384     if ( aHelper.IsQuadraticMesh() != SMESH_MesherHelper::LINEAR )
385     {
386       aHelper.FixQuadraticElements( sm->GetComputeError() );
387     }
388   }
389   return ret;
390 }
391
392 //=============================================================================
393 /*!
394  * Prepare Compute a mesh
395  */
396 //=============================================================================
397 void SMESH_Gen::PrepareCompute(SMESH_Mesh &          aMesh,
398                                const TopoDS_Shape &  aShape)
399 {
400   _compute_canceled = false;
401   resetCurrentSubMesh();
402 }
403
404 //=============================================================================
405 /*!
406  * Cancel Compute a mesh
407  */
408 //=============================================================================
409 void SMESH_Gen::CancelCompute(SMESH_Mesh &          aMesh,
410                               const TopoDS_Shape &  aShape)
411 {
412   _compute_canceled = true;
413   if ( const SMESH_subMesh* sm = GetCurrentSubMesh() )
414   {
415     const_cast< SMESH_subMesh* >( sm )->ComputeStateEngine( SMESH_subMesh::COMPUTE_CANCELED );
416   }
417   resetCurrentSubMesh();
418 }
419
420 //================================================================================
421 /*!
422  * \brief Returns a sub-mesh being currently computed
423  */
424 //================================================================================
425
426 const SMESH_subMesh* SMESH_Gen::GetCurrentSubMesh() const
427 {
428   return _sm_current.empty() ? 0 : _sm_current.back();
429 }
430
431 //================================================================================
432 /*!
433  * \brief Sets a sub-mesh being currently computed.
434  *
435  * An algorithm can call Compute() for a sub-shape, hence we keep a stack of sub-meshes
436  */
437 //================================================================================
438
439 void SMESH_Gen::setCurrentSubMesh(SMESH_subMesh* sm)
440 {
441   if ( sm )
442     _sm_current.push_back( sm );
443
444   else if ( !_sm_current.empty() )
445     _sm_current.pop_back();
446 }
447
448 void SMESH_Gen::resetCurrentSubMesh()
449 {
450   _sm_current.clear();
451 }
452
453 //=============================================================================
454 /*!
455  * Evaluate a mesh
456  */
457 //=============================================================================
458
459 bool SMESH_Gen::Evaluate(SMESH_Mesh &          aMesh,
460                          const TopoDS_Shape &  aShape,
461                          MapShapeNbElems&      aResMap,
462                          const bool            anUpward,
463                          TSetOfInt*            aShapesId)
464 {
465   bool ret = true;
466
467   SMESH_subMesh *sm = aMesh.GetSubMesh(aShape);
468
469   const bool includeSelf = true;
470   const bool complexShapeFirst = true;
471   SMESH_subMeshIteratorPtr smIt;
472
473   if ( anUpward ) { // is called from below code here
474     // -----------------------------------------------
475     // mesh all the sub-shapes starting from vertices
476     // -----------------------------------------------
477     smIt = sm->getDependsOnIterator(includeSelf, !complexShapeFirst);
478     while ( smIt->more() ) {
479       SMESH_subMesh* smToCompute = smIt->next();
480
481       // do not mesh vertices of a pseudo shape
482       const TopAbs_ShapeEnum shapeType = smToCompute->GetSubShape().ShapeType();
483       //if ( !aMesh.HasShapeToMesh() && shapeType == TopAbs_VERTEX )
484       //  continue;
485       if ( !aMesh.HasShapeToMesh() ) {
486         if( shapeType == TopAbs_VERTEX || shapeType == TopAbs_WIRE ||
487             shapeType == TopAbs_SHELL )
488           continue;
489       }
490
491       smToCompute->Evaluate(aResMap);
492       if( aShapesId )
493         aShapesId->insert( smToCompute->GetId() );
494     }
495     return ret;
496   }
497   else {
498     // -----------------------------------------------------------------
499     // apply algos that DO NOT require Discreteized boundaries and DO NOT
500     // support sub-meshes, starting from the most complex shapes
501     // and collect sub-meshes with algos that DO support sub-meshes
502     // -----------------------------------------------------------------
503     list< SMESH_subMesh* > smWithAlgoSupportingSubmeshes;
504     smIt = sm->getDependsOnIterator(includeSelf, complexShapeFirst);
505     while ( smIt->more() ) {
506       SMESH_subMesh* smToCompute = smIt->next();
507       const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
508       const int aShapeDim = GetShapeDim( aSubShape );
509       if ( aShapeDim < 1 ) break;
510       
511       SMESH_Algo* algo = GetAlgo( smToCompute );
512       if ( algo && !algo->NeedDiscreteBoundary() ) {
513         if ( algo->SupportSubmeshes() ) {
514           smWithAlgoSupportingSubmeshes.push_front( smToCompute );
515         }
516         else {
517           smToCompute->Evaluate(aResMap);
518           if ( aShapesId )
519             aShapesId->insert( smToCompute->GetId() );
520         }
521       }
522     }
523
524     // ------------------------------------------------------------
525     // sort list of meshes according to mesh order
526     // ------------------------------------------------------------
527     std::vector< SMESH_subMesh* > smVec( smWithAlgoSupportingSubmeshes.begin(),
528                                          smWithAlgoSupportingSubmeshes.end() );
529     aMesh.SortByMeshOrder( smVec );
530
531     // ------------------------------------------------------------
532     // compute sub-meshes under shapes with algos that DO NOT require
533     // Discreteized boundaries and DO support sub-meshes
534     // ------------------------------------------------------------
535     // start from lower shapes
536     for ( size_t i = 0; i < smVec.size(); ++i )
537     {
538       sm = smVec[i];
539
540       // get a shape the algo is assigned to
541       TopoDS_Shape algoShape;
542       if ( !GetAlgo( sm, & algoShape ))
543         continue; // strange...
544
545       // look for more local algos
546       smIt = sm->getDependsOnIterator(!includeSelf, !complexShapeFirst);
547       while ( smIt->more() ) {
548         SMESH_subMesh* smToCompute = smIt->next();
549
550         const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
551         const int aShapeDim = GetShapeDim( aSubShape );
552         if ( aShapeDim < 1 ) continue;
553
554         SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() );
555         filter
556           .And( SMESH_HypoFilter::IsApplicableTo( aSubShape ))
557           .And( SMESH_HypoFilter::IsMoreLocalThan( algoShape, aMesh ));
558
559         if ( SMESH_Algo* subAlgo = (SMESH_Algo*) aMesh.GetHypothesis( smToCompute, filter, true ))
560         {
561           if ( ! subAlgo->NeedDiscreteBoundary() ) continue;
562           SMESH_Hypothesis::Hypothesis_Status status;
563           if ( subAlgo->CheckHypothesis( aMesh, aSubShape, status ))
564             // mesh a lower smToCompute starting from vertices
565             Evaluate( aMesh, aSubShape, aResMap, /*anUpward=*/true, aShapesId );
566         }
567       }
568     }
569     // ----------------------------------------------------------
570     // apply the algos that do not require Discreteized boundaries
571     // ----------------------------------------------------------
572     for ( size_t i = 0; i < smVec.size(); ++i )
573     {
574       sm = smVec[i];
575       sm->Evaluate(aResMap);
576       if ( aShapesId )
577         aShapesId->insert( sm->GetId() );
578     }
579
580     // -----------------------------------------------
581     // mesh the rest sub-shapes starting from vertices
582     // -----------------------------------------------
583     ret = Evaluate( aMesh, aShape, aResMap, /*anUpward=*/true, aShapesId );
584   }
585
586   MESSAGE( "VSR - SMESH_Gen::Evaluate() finished, OK = " << ret);
587   return ret;
588 }
589
590
591 //=======================================================================
592 //function : checkConformIgnoredAlgos
593 //purpose  :
594 //=======================================================================
595
596 static bool checkConformIgnoredAlgos(SMESH_Mesh&               aMesh,
597                                      SMESH_subMesh*            aSubMesh,
598                                      const SMESH_Algo*         aGlobIgnoAlgo,
599                                      const SMESH_Algo*         aLocIgnoAlgo,
600                                      bool &                    checkConform,
601                                      set<SMESH_subMesh*>&      aCheckedMap,
602                                      list< SMESH_Gen::TAlgoStateError > & theErrors)
603 {
604   ASSERT( aSubMesh );
605   if ( aSubMesh->GetSubShape().ShapeType() == TopAbs_VERTEX)
606     return true;
607
608
609   bool ret = true;
610
611   const list<const SMESHDS_Hypothesis*>& listHyp =
612     aMesh.GetMeshDS()->GetHypothesis( aSubMesh->GetSubShape() );
613   list<const SMESHDS_Hypothesis*>::const_iterator it=listHyp.begin();
614   for ( ; it != listHyp.end(); it++)
615   {
616     const SMESHDS_Hypothesis * aHyp = *it;
617     if (aHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO)
618       continue;
619
620     const SMESH_Algo* algo = dynamic_cast<const SMESH_Algo*> (aHyp);
621     ASSERT ( algo );
622
623     if ( aLocIgnoAlgo ) // algo is hidden by a local algo of upper dim
624     {
625       theErrors.push_back( SMESH_Gen::TAlgoStateError() );
626       theErrors.back().Set( SMESH_Hypothesis::HYP_HIDDEN_ALGO, algo, false );
627       INFOS( "Local <" << algo->GetName() << "> is hidden by local <"
628             << aLocIgnoAlgo->GetName() << ">");
629     }
630     else
631     {
632       bool       isGlobal = (aMesh.IsMainShape( aSubMesh->GetSubShape() ));
633       int             dim = algo->GetDim();
634       int aMaxGlobIgnoDim = ( aGlobIgnoAlgo ? aGlobIgnoAlgo->GetDim() : -1 );
635       bool    isNeededDim = ( aGlobIgnoAlgo ? aGlobIgnoAlgo->NeedLowerHyps( dim ) : false );
636
637       if (( dim < aMaxGlobIgnoDim && !isNeededDim ) &&
638           ( isGlobal || !aGlobIgnoAlgo->SupportSubmeshes() ))
639       {
640         // algo is hidden by a global algo
641         theErrors.push_back( SMESH_Gen::TAlgoStateError() );
642         theErrors.back().Set( SMESH_Hypothesis::HYP_HIDDEN_ALGO, algo, true );
643         INFOS( ( isGlobal ? "Global" : "Local" )
644               << " <" << algo->GetName() << "> is hidden by global <"
645               << aGlobIgnoAlgo->GetName() << ">");
646       }
647       else if ( !algo->NeedDiscreteBoundary() && !isGlobal)
648       {
649         // local algo is not hidden and hides algos on sub-shapes
650         if (checkConform && !aSubMesh->IsConform( algo ))
651         {
652           ret = false;
653           checkConform = false; // no more check conformity
654           INFOS( "ERROR: Local <" << algo->GetName() <<
655                 "> would produce not conform mesh: "
656                 "<Not Conform Mesh Allowed> hypotesis is missing");
657           theErrors.push_back( SMESH_Gen::TAlgoStateError() );
658           theErrors.back().Set( SMESH_Hypothesis::HYP_NOTCONFORM, algo, false );
659         }
660
661         // sub-algos will be hidden by a local <algo> if <algo> does not support sub-meshes
662         if ( algo->SupportSubmeshes() )
663           algo = 0;
664         SMESH_subMeshIteratorPtr revItSub =
665           aSubMesh->getDependsOnIterator( /*includeSelf=*/false, /*complexShapeFirst=*/true);
666         bool checkConform2 = false;
667         while ( revItSub->more() )
668         {
669           SMESH_subMesh* sm = revItSub->next();
670           checkConformIgnoredAlgos (aMesh, sm, aGlobIgnoAlgo,
671                                     algo, checkConform2, aCheckedMap, theErrors);
672           aCheckedMap.insert( sm );
673         }
674       }
675     }
676   }
677
678   return ret;
679 }
680
681 //=======================================================================
682 //function : checkMissing
683 //purpose  : notify on missing hypothesis
684 //           Return false if algo or hipothesis is missing
685 //=======================================================================
686
687 static bool checkMissing(SMESH_Gen*                aGen,
688                          SMESH_Mesh&               aMesh,
689                          SMESH_subMesh*            aSubMesh,
690                          const int                 aTopAlgoDim,
691                          bool*                     globalChecked,
692                          const bool                checkNoAlgo,
693                          set<SMESH_subMesh*>&      aCheckedMap,
694                          list< SMESH_Gen::TAlgoStateError > & theErrors)
695 {
696   switch ( aSubMesh->GetSubShape().ShapeType() )
697   {
698   case TopAbs_EDGE:
699   case TopAbs_FACE:
700   case TopAbs_SOLID: break; // check this sub-mesh, it can be meshed
701   default:
702     return true; // not meshable sub-mesh
703   }
704   if ( aCheckedMap.count( aSubMesh ))
705     return true;
706
707   int ret = true;
708   SMESH_Algo* algo = 0;
709
710   switch (aSubMesh->GetAlgoState())
711   {
712   case SMESH_subMesh::NO_ALGO: {
713     if (checkNoAlgo)
714     {
715       // should there be any algo?
716       int shapeDim = SMESH_Gen::GetShapeDim( aSubMesh->GetSubShape() );
717       if (aTopAlgoDim > shapeDim)
718       {
719         MESSAGE( "ERROR: " << shapeDim << "D algorithm is missing" );
720         ret = false;
721         theErrors.push_back( SMESH_Gen::TAlgoStateError() );
722         theErrors.back().Set( SMESH_Hypothesis::HYP_MISSING, shapeDim, true );
723       }
724     }
725     return ret;
726   }
727   case SMESH_subMesh::MISSING_HYP: {
728     // notify if an algo missing hyp is attached to aSubMesh
729     algo = aSubMesh->GetAlgo();
730     ASSERT( algo );
731     bool IsGlobalHypothesis = aGen->IsGlobalHypothesis( algo, aMesh );
732     if (!IsGlobalHypothesis || !globalChecked[ algo->GetDim() ])
733     {
734       TAlgoStateErrorName errName = SMESH_Hypothesis::HYP_MISSING;
735       SMESH_Hypothesis::Hypothesis_Status status;
736       algo->CheckHypothesis( aMesh, aSubMesh->GetSubShape(), status );
737       if ( status == SMESH_Hypothesis::HYP_BAD_PARAMETER ) {
738         MESSAGE( "ERROR: hypothesis of " << (IsGlobalHypothesis ? "Global " : "Local ")
739                  << "<" << algo->GetName() << "> has a bad parameter value");
740         errName = status;
741       } else if ( status == SMESH_Hypothesis::HYP_BAD_GEOMETRY ) {
742         MESSAGE( "ERROR: " << (IsGlobalHypothesis ? "Global " : "Local ")
743                  << "<" << algo->GetName() << "> assigned to mismatching geometry");
744         errName = status;
745       } else {
746         MESSAGE( "ERROR: " << (IsGlobalHypothesis ? "Global " : "Local ")
747                  << "<" << algo->GetName() << "> misses some hypothesis");
748       }
749       if (IsGlobalHypothesis)
750         globalChecked[ algo->GetDim() ] = true;
751       theErrors.push_back( SMESH_Gen::TAlgoStateError() );
752       theErrors.back().Set( errName, algo, IsGlobalHypothesis );
753     }
754     ret = false;
755     break;
756   }
757   case SMESH_subMesh::HYP_OK:
758     algo = aSubMesh->GetAlgo();
759     ret = true;
760     if (!algo->NeedDiscreteBoundary())
761     {
762       SMESH_subMeshIteratorPtr itsub = aSubMesh->getDependsOnIterator( /*includeSelf=*/false,
763                                                                        /*complexShapeFirst=*/false);
764       while ( itsub->more() )
765         aCheckedMap.insert( itsub->next() );
766     }
767     break;
768   default: ASSERT(0);
769   }
770
771   // do not check under algo that hides sub-algos or
772   // re-start checking NO_ALGO state
773   ASSERT (algo);
774   bool isTopLocalAlgo =
775     ( aTopAlgoDim <= algo->GetDim() && !aGen->IsGlobalHypothesis( algo, aMesh ));
776   if (!algo->NeedDiscreteBoundary() || isTopLocalAlgo)
777   {
778     bool checkNoAlgo2 = ( algo->NeedDiscreteBoundary() );
779     SMESH_subMeshIteratorPtr itsub = aSubMesh->getDependsOnIterator( /*includeSelf=*/false,
780                                                                      /*complexShapeFirst=*/true);
781     while ( itsub->more() )
782     {
783       // sub-meshes should not be checked further more
784       SMESH_subMesh* sm = itsub->next();
785
786       if (isTopLocalAlgo)
787       {
788         //check algo on sub-meshes
789         int aTopAlgoDim2 = algo->GetDim();
790         if (!checkMissing (aGen, aMesh, sm, aTopAlgoDim2,
791                            globalChecked, checkNoAlgo2, aCheckedMap, theErrors))
792         {
793           ret = false;
794           if (sm->GetAlgoState() == SMESH_subMesh::NO_ALGO )
795             checkNoAlgo2 = false;
796         }
797       }
798       aCheckedMap.insert( sm );
799     }
800   }
801   return ret;
802 }
803
804 //=======================================================================
805 //function : CheckAlgoState
806 //purpose  : notify on bad state of attached algos, return false
807 //           if Compute() would fail because of some algo bad state
808 //=======================================================================
809
810 bool SMESH_Gen::CheckAlgoState(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
811 {
812   list< TAlgoStateError > errors;
813   return GetAlgoState( aMesh, aShape, errors );
814 }
815
816 //=======================================================================
817 //function : GetAlgoState
818 //purpose  : notify on bad state of attached algos, return false
819 //           if Compute() would fail because of some algo bad state
820 //           theErrors list contains problems description
821 //=======================================================================
822
823 bool SMESH_Gen::GetAlgoState(SMESH_Mesh&               theMesh,
824                              const TopoDS_Shape&       theShape,
825                              list< TAlgoStateError > & theErrors)
826 {
827   bool ret = true;
828   bool hasAlgo = false;
829
830   SMESH_subMesh*          sm = theMesh.GetSubMesh(theShape);
831   const SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
832   TopoDS_Shape     mainShape = meshDS->ShapeToMesh();
833
834   // -----------------
835   // get global algos
836   // -----------------
837
838   const SMESH_Algo* aGlobAlgoArr[] = {0,0,0,0};
839
840   const list<const SMESHDS_Hypothesis*>& listHyp = meshDS->GetHypothesis( mainShape );
841   list<const SMESHDS_Hypothesis*>::const_iterator it=listHyp.begin();
842   for ( ; it != listHyp.end(); it++)
843   {
844     const SMESHDS_Hypothesis * aHyp = *it;
845     if (aHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO)
846       continue;
847
848     const SMESH_Algo* algo = dynamic_cast<const SMESH_Algo*> (aHyp);
849     ASSERT ( algo );
850
851     int dim = algo->GetDim();
852     aGlobAlgoArr[ dim ] = algo;
853
854     hasAlgo = true;
855   }
856
857   // --------------------------------------------------------
858   // info on algos that will be ignored because of ones that
859   // don't NeedDiscreteBoundary() attached to super-shapes,
860   // check that a conform mesh will be produced
861   // --------------------------------------------------------
862
863
864   // find a global algo possibly hiding sub-algos
865   int dim;
866   const SMESH_Algo* aGlobIgnoAlgo = 0;
867   for (dim = 3; dim > 0; dim--)
868   {
869     if (aGlobAlgoArr[ dim ] &&
870         !aGlobAlgoArr[ dim ]->NeedDiscreteBoundary() /*&&
871         !aGlobAlgoArr[ dim ]->SupportSubmeshes()*/ )
872     {
873       aGlobIgnoAlgo = aGlobAlgoArr[ dim ];
874       break;
875     }
876   }
877
878   set<SMESH_subMesh*> aCheckedSubs;
879   bool checkConform = ( !theMesh.IsNotConformAllowed() );
880
881   // loop on theShape and its sub-shapes
882   SMESH_subMeshIteratorPtr revItSub = sm->getDependsOnIterator( /*includeSelf=*/true,
883                                                                 /*complexShapeFirst=*/true);
884   while ( revItSub->more() )
885   {
886     SMESH_subMesh* smToCheck = revItSub->next();
887     if ( smToCheck->GetSubShape().ShapeType() == TopAbs_VERTEX)
888       break;
889
890     if ( aCheckedSubs.insert( smToCheck ).second ) // not yet checked
891       if (!checkConformIgnoredAlgos (theMesh, smToCheck, aGlobIgnoAlgo,
892                                      0, checkConform, aCheckedSubs, theErrors))
893         ret = false;
894
895     if ( smToCheck->GetAlgoState() != SMESH_subMesh::NO_ALGO )
896       hasAlgo = true;
897   }
898
899   // ----------------------------------------------------------------
900   // info on missing hypothesis and find out if all needed algos are
901   // well defined
902   // ----------------------------------------------------------------
903
904   // find max dim of global algo
905   int aTopAlgoDim = 0;
906   for (dim = 3; dim > 0; dim--)
907   {
908     if (aGlobAlgoArr[ dim ])
909     {
910       aTopAlgoDim = dim;
911       break;
912     }
913   }
914   bool checkNoAlgo = theMesh.HasShapeToMesh() ? bool( aTopAlgoDim ) : false;
915   bool globalChecked[] = { false, false, false, false };
916
917   // loop on theShape and its sub-shapes
918   aCheckedSubs.clear();
919   revItSub = sm->getDependsOnIterator( /*includeSelf=*/true, /*complexShapeFirst=*/true);
920   while ( revItSub->more() )
921   {
922     SMESH_subMesh* smToCheck = revItSub->next();
923     if ( smToCheck->GetSubShape().ShapeType() == TopAbs_VERTEX)
924       break;
925
926     if (!checkMissing (this, theMesh, smToCheck, aTopAlgoDim,
927                        globalChecked, checkNoAlgo, aCheckedSubs, theErrors))
928     {
929       ret = false;
930       if (smToCheck->GetAlgoState() == SMESH_subMesh::NO_ALGO )
931         checkNoAlgo = false;
932     }
933   }
934
935   if ( !hasAlgo ) {
936     ret = false;
937     theErrors.push_back( TAlgoStateError() );
938     theErrors.back().Set( SMESH_Hypothesis::HYP_MISSING, theMesh.HasShapeToMesh() ? 1 : 3, true );
939   }
940
941   return ret;
942 }
943
944 //=======================================================================
945 //function : IsGlobalHypothesis
946 //purpose  : check if theAlgo is attached to the main shape
947 //=======================================================================
948
949 bool SMESH_Gen::IsGlobalHypothesis(const SMESH_Hypothesis* theHyp, SMESH_Mesh& aMesh)
950 {
951   SMESH_HypoFilter filter( SMESH_HypoFilter::Is( theHyp ));
952   return aMesh.GetHypothesis( aMesh.GetMeshDS()->ShapeToMesh(), filter, false );
953 }
954
955 //================================================================================
956 /*!
957  * \brief Return paths to xml files of plugins
958  */
959 //================================================================================
960
961 std::vector< std::string > SMESH_Gen::GetPluginXMLPaths()
962 {
963   // Get paths to xml files of plugins
964   vector< string > xmlPaths;
965   string sep;
966   if ( const char* meshersList = getenv("SMESH_MeshersList") )
967   {
968     string meshers = meshersList, plugin;
969     string::size_type from = 0, pos;
970     while ( from < meshers.size() )
971     {
972       // cut off plugin name
973       pos = meshers.find( ':', from );
974       if ( pos != string::npos )
975         plugin = meshers.substr( from, pos-from );
976       else
977         plugin = meshers.substr( from ), pos = meshers.size();
978       from = pos + 1;
979
980       // get PLUGIN_ROOT_DIR path
981       string rootDirVar, pluginSubDir = plugin;
982       if ( plugin == "StdMeshers" )
983         rootDirVar = "SMESH", pluginSubDir = "smesh";
984       else
985         for ( pos = 0; pos < plugin.size(); ++pos )
986           rootDirVar += toupper( plugin[pos] );
987       rootDirVar += "_ROOT_DIR";
988
989       const char* rootDir = getenv( rootDirVar.c_str() );
990       if ( !rootDir || strlen(rootDir) == 0 )
991       {
992         rootDirVar = plugin + "_ROOT_DIR"; // HexoticPLUGIN_ROOT_DIR
993         rootDir = getenv( rootDirVar.c_str() );
994         if ( !rootDir || strlen(rootDir) == 0 ) continue;
995       }
996
997       // get a separator from rootDir
998       for ( pos = strlen( rootDir )-1; pos >= 0 && sep.empty(); --pos )
999         if ( rootDir[pos] == '/' || rootDir[pos] == '\\' )
1000         {
1001           sep = rootDir[pos];
1002           break;
1003         }
1004 #ifdef WIN32
1005       if (sep.empty() ) sep = "\\";
1006 #else
1007       if (sep.empty() ) sep = "/";
1008 #endif
1009
1010       // get a path to resource file
1011       string xmlPath = rootDir;
1012       if ( xmlPath[ xmlPath.size()-1 ] != sep[0] )
1013         xmlPath += sep;
1014       xmlPath += "share" + sep + "salome" + sep + "resources" + sep;
1015       for ( pos = 0; pos < pluginSubDir.size(); ++pos )
1016         xmlPath += tolower( pluginSubDir[pos] );
1017       xmlPath += sep + plugin + ".xml";
1018       bool fileOK;
1019 #ifdef WIN32
1020       fileOK = (GetFileAttributes(xmlPath.c_str()) != INVALID_FILE_ATTRIBUTES);
1021 #else
1022       fileOK = (access(xmlPath.c_str(), F_OK) == 0);
1023 #endif
1024       if ( fileOK )
1025         xmlPaths.push_back( xmlPath );
1026     }
1027   }
1028
1029   return xmlPaths;
1030 }
1031
1032 //=============================================================================
1033 /*!
1034  * Finds algo to mesh a shape. Optionally returns a shape the found algo is bound to
1035  */
1036 //=============================================================================
1037
1038 SMESH_Algo *SMESH_Gen::GetAlgo(SMESH_Mesh &         aMesh,
1039                                const TopoDS_Shape & aShape,
1040                                TopoDS_Shape*        assignedTo)
1041 {
1042   return GetAlgo( aMesh.GetSubMesh( aShape ), assignedTo );
1043 }
1044
1045 //=============================================================================
1046 /*!
1047  * Finds algo to mesh a sub-mesh. Optionally returns a shape the found algo is bound to
1048  */
1049 //=============================================================================
1050
1051 SMESH_Algo *SMESH_Gen::GetAlgo(SMESH_subMesh * aSubMesh,
1052                                TopoDS_Shape*   assignedTo)
1053 {
1054   if ( !aSubMesh ) return 0;
1055
1056   const TopoDS_Shape & aShape = aSubMesh->GetSubShape();
1057   SMESH_Mesh&          aMesh  = *aSubMesh->GetFather();
1058
1059   SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() );
1060   filter.And( filter.IsApplicableTo( aShape ));
1061
1062   typedef SMESH_Algo::Features AlgoData;
1063
1064   TopoDS_Shape assignedToShape;
1065   SMESH_Algo* algo =
1066     (SMESH_Algo*) aMesh.GetHypothesis( aSubMesh, filter, true, &assignedToShape );
1067
1068   if ( algo &&
1069        aShape.ShapeType() == TopAbs_FACE &&
1070        !aShape.IsSame( assignedToShape ) &&
1071        SMESH_MesherHelper::NbAncestors( aShape, aMesh, TopAbs_SOLID ) > 1 )
1072   {
1073     // Issue 0021559. If there is another 2D algo with different types of output
1074     // elements that can be used to mesh aShape, and 3D algos on adjacent SOLIDs
1075     // have different types of input elements, we choose a most appropriate 2D algo.
1076
1077     // try to find a concurrent 2D algo
1078     filter.AndNot( filter.Is( algo ));
1079     TopoDS_Shape assignedToShape2;
1080     SMESH_Algo* algo2 =
1081       (SMESH_Algo*) aMesh.GetHypothesis( aSubMesh, filter, true, &assignedToShape2 );
1082     if ( algo2 &&                                                  // algo found
1083          !assignedToShape2.IsSame( aMesh.GetShapeToMesh() ) &&     // algo is local
1084          ( SMESH_MesherHelper::GetGroupType( assignedToShape2 ) == // algo of the same level
1085            SMESH_MesherHelper::GetGroupType( assignedToShape )) &&
1086          aMesh.IsOrderOK( aMesh.GetSubMesh( assignedToShape2 ),    // no forced order
1087                           aMesh.GetSubMesh( assignedToShape  )))
1088     {
1089       // get algos on the adjacent SOLIDs
1090       filter.Init( filter.IsAlgo() ).And( filter.HasDim( 3 ));
1091       vector< SMESH_Algo* > algos3D;
1092       PShapeIteratorPtr solidIt = SMESH_MesherHelper::GetAncestors( aShape, aMesh,
1093                                                                     TopAbs_SOLID );
1094       while ( const TopoDS_Shape* solid = solidIt->next() )
1095         if ( SMESH_Algo* algo3D = (SMESH_Algo*) aMesh.GetHypothesis( *solid, filter, true ))
1096         {
1097           algos3D.push_back( algo3D );
1098           filter.AndNot( filter.HasName( algo3D->GetName() ));
1099         }
1100       // check compatibility of algos
1101       if ( algos3D.size() > 1 )
1102       {
1103         const AlgoData& algoData    = algo->SMESH_Algo::GetFeatures();
1104         const AlgoData& algoData2   = algo2->SMESH_Algo::GetFeatures();
1105         const AlgoData& algoData3d0 = algos3D[0]->SMESH_Algo::GetFeatures();
1106         const AlgoData& algoData3d1 = algos3D[1]->SMESH_Algo::GetFeatures();
1107         if (( algoData2.IsCompatible( algoData3d0 ) &&
1108               algoData2.IsCompatible( algoData3d1 ))
1109             &&
1110             !(algoData.IsCompatible( algoData3d0 ) &&
1111               algoData.IsCompatible( algoData3d1 )))
1112           algo = algo2;
1113       }
1114     }
1115   }
1116
1117   if ( assignedTo && algo )
1118     * assignedTo = assignedToShape;
1119
1120   return algo;
1121 }
1122
1123 //=============================================================================
1124 /*!
1125  * Returns StudyContextStruct for a study
1126  */
1127 //=============================================================================
1128
1129 StudyContextStruct *SMESH_Gen::GetStudyContext(int studyId)
1130 {
1131   // Get studyContext, create it if it does'nt exist, with a SMESHDS_Document
1132
1133   if (_mapStudyContext.find(studyId) == _mapStudyContext.end())
1134   {
1135     _mapStudyContext[studyId] = new StudyContextStruct;
1136     _mapStudyContext[studyId]->myDocument = new SMESHDS_Document(studyId);
1137   }
1138   StudyContextStruct *myStudyContext = _mapStudyContext[studyId];
1139   return myStudyContext;
1140 }
1141
1142 //================================================================================
1143 /*!
1144  * \brief Return shape dimension by TopAbs_ShapeEnum
1145  */
1146 //================================================================================
1147
1148 int SMESH_Gen::GetShapeDim(const TopAbs_ShapeEnum & aShapeType)
1149 {
1150   static vector<int> dim;
1151   if ( dim.empty() )
1152   {
1153     dim.resize( TopAbs_SHAPE, -1 );
1154     dim[ TopAbs_COMPOUND ]  = MeshDim_3D;
1155     dim[ TopAbs_COMPSOLID ] = MeshDim_3D;
1156     dim[ TopAbs_SOLID ]     = MeshDim_3D;
1157     dim[ TopAbs_SHELL ]     = MeshDim_2D;
1158     dim[ TopAbs_FACE  ]     = MeshDim_2D;
1159     dim[ TopAbs_WIRE ]      = MeshDim_1D;
1160     dim[ TopAbs_EDGE ]      = MeshDim_1D;
1161     dim[ TopAbs_VERTEX ]    = MeshDim_0D;
1162   }
1163   return dim[ aShapeType ];
1164 }
1165
1166 //=============================================================================
1167 /*!
1168  * Genarate a new id unique withing this Gen
1169  */
1170 //=============================================================================
1171
1172 int SMESH_Gen::GetANewId()
1173 {
1174   return _hypId++;
1175 }