Salome HOME
bos #24400 [CEA] Option in SALOME for not storing in med files the indices (number...
[modules/smesh.git] / src / SMESH / SMESH_Mesh.cxx
1 // Copyright (C) 2007-2021  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 //  File   : SMESH_Mesh.cxx
24 //  Author : Paul RASCLE, EDF
25 //  Module : SMESH
26 //
27 #include "SMESH_Mesh.hxx"
28 #include "SMESH_MesherHelper.hxx"
29 #include "SMDS_MeshVolume.hxx"
30 #include "SMDS_SetIterator.hxx"
31 #include "SMESHDS_Document.hxx"
32 #include "SMESHDS_Group.hxx"
33 #include "SMESHDS_GroupOnGeom.hxx"
34 #include "SMESHDS_Script.hxx"
35 #include "SMESHDS_TSubMeshHolder.hxx"
36 #include "SMESH_Gen.hxx"
37 #include "SMESH_Group.hxx"
38 #include "SMESH_HypoFilter.hxx"
39 #include "SMESH_Hypothesis.hxx"
40 #include "SMESH_subMesh.hxx"
41
42 #include "utilities.h"
43
44 #include "DriverDAT_W_SMDS_Mesh.h"
45 #include "DriverGMF_Read.hxx"
46 #include "DriverGMF_Write.hxx"
47 #include "DriverMED_R_SMESHDS_Mesh.h"
48 #include "DriverMED_W_SMESHDS_Mesh.h"
49 #include "DriverSTL_R_SMDS_Mesh.h"
50 #include "DriverSTL_W_SMDS_Mesh.h"
51 #include "DriverUNV_R_SMDS_Mesh.h"
52 #include "DriverUNV_W_SMDS_Mesh.h"
53 #ifdef WITH_CGNS
54 #include "DriverCGNS_Read.hxx"
55 #include "DriverCGNS_Write.hxx"
56 #endif
57
58 #include <GEOMUtils.hxx>
59
60 #undef _Precision_HeaderFile
61 #include <BRepBndLib.hxx>
62 #include <BRepPrimAPI_MakeBox.hxx>
63 #include <Bnd_Box.hxx>
64 #include <TColStd_MapOfInteger.hxx>
65 #include <TopExp.hxx>
66 #include <TopExp_Explorer.hxx>
67 #include <TopTools_ListIteratorOfListOfShape.hxx>
68 #include <TopTools_ListOfShape.hxx>
69 #include <TopTools_MapOfShape.hxx>
70 #include <TopoDS_Iterator.hxx>
71
72 #include "SMESH_TryCatch.hxx" // include after OCCT headers!
73
74 #include "Utils_ExceptHandlers.hxx"
75
76 #ifndef WIN32
77 #include <boost/thread/thread.hpp>
78 #include <boost/bind.hpp>
79 #else 
80 #include <pthread.h>
81 #endif
82
83 // maximum stored group name length in MED file
84 #define MAX_MED_GROUP_NAME_LENGTH 80
85
86 #ifdef _DEBUG_
87 static int MYDEBUG = 0;
88 #else
89 static int MYDEBUG = 0;
90 #endif
91
92 #define cSMESH_Hyp(h) static_cast<const SMESH_Hypothesis*>(h)
93
94 typedef SMESH_HypoFilter THypType;
95
96 class SMESH_Mesh::SubMeshHolder : public SMESHDS_TSubMeshHolder< SMESH_subMesh >
97 {
98 };
99
100 //=============================================================================
101 /*!
102  * 
103  */
104 //=============================================================================
105
106 SMESH_Mesh::SMESH_Mesh(int               theLocalId,
107                        SMESH_Gen*        theGen,
108                        bool              theIsEmbeddedMode,
109                        SMESHDS_Document* theDocument):
110   _groupId( 0 ), _nbSubShapes( 0 )
111 {
112   if(MYDEBUG) MESSAGE("SMESH_Mesh::SMESH_Mesh(int localId)");
113   _id            = theLocalId;
114   _gen           = theGen;
115   _document    = theDocument;
116   _meshDS      = theDocument->NewMesh(theIsEmbeddedMode,theLocalId);
117   _isShapeToMesh = false;
118   _isAutoColor   = false;
119   _isModified    = false;
120   _shapeDiagonal = 0.0;
121   _callUp        = NULL;
122   _meshDS->ShapeToMesh( PseudoShape() );
123   _subMeshHolder = new SubMeshHolder;
124
125   // assure unique persistent ID
126   if ( _document->NbMeshes() > 1 )
127   {
128     std::set< int > ids;
129     for ( _document->InitMeshesIterator(); _document->MoreMesh(); )
130     {
131       SMESHDS_Mesh * meshDS =_document->NextMesh();
132       if ( meshDS != _meshDS )
133         ids.insert( meshDS->GetPersistentId() );
134     }
135
136     if ( ids.count( _meshDS->GetPersistentId() ))
137     {
138       int uniqueID = *ids.rbegin() + 1;
139       _meshDS->SetPersistentId( uniqueID );
140     }
141   }
142 }
143
144 //================================================================================
145 /*!
146  * \brief Constructor of SMESH_Mesh being a base of some descendant class
147  */
148 //================================================================================
149
150 SMESH_Mesh::SMESH_Mesh():
151   _id(-1),
152   _groupId( 0 ),
153   _nbSubShapes( 0 ),
154   _isShapeToMesh( false ),
155   _document( 0 ),
156   _meshDS( 0 ),
157   _gen( 0 ),
158   _isAutoColor( false ),
159   _isModified( false ),
160   _shapeDiagonal( 0.0 ),
161   _callUp( 0 )
162 {
163   _subMeshHolder = new SubMeshHolder;
164 }
165
166 namespace
167 {
168 #ifndef WIN32
169   void deleteMeshDS(SMESHDS_Mesh* meshDS)
170   {
171     //cout << "deleteMeshDS( " << meshDS << endl;
172     delete meshDS;
173   }
174 #else
175   static void* deleteMeshDS(void* meshDS)
176   {
177     //cout << "deleteMeshDS( " << meshDS << endl;
178     SMESHDS_Mesh* m = (SMESHDS_Mesh*)meshDS;
179     if(m) {
180       delete m;
181     }
182     return 0;
183   }
184 #endif
185 }
186
187 //=============================================================================
188 /*!
189  *
190  */
191 //=============================================================================
192
193 SMESH_Mesh::~SMESH_Mesh()
194 {
195   if(MYDEBUG) MESSAGE("SMESH_Mesh::~SMESH_Mesh");
196
197   if ( _document ) // avoid destructing _meshDS from ~SMESH_Gen()
198     _document->RemoveMesh( _id );
199   _document = 0;
200
201   // remove self from studyContext
202   if ( _gen )
203   {
204     StudyContextStruct * studyContext = _gen->GetStudyContext();
205     studyContext->mapMesh.erase( _id );
206   }
207
208   _meshDS->ClearMesh();
209
210   // issue 0020340: EDF 1022 SMESH : Crash with FindNodeClosestTo in a second new study
211   //   Notify event listeners at least that something happens
212   if ( SMESH_subMesh * sm = GetSubMeshContaining(1))
213     sm->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
214
215   // delete groups
216   std::map < int, SMESH_Group * >::iterator itg;
217   for (itg = _mapGroup.begin(); itg != _mapGroup.end(); itg++) {
218     SMESH_Group *aGroup = (*itg).second;
219     delete aGroup;
220   }
221   _mapGroup.clear();
222
223   // delete sub-meshes
224   delete _subMeshHolder;
225
226   if ( _callUp) delete _callUp;
227   _callUp = 0;
228
229   if ( _meshDS ) {
230     // delete _meshDS, in a thread in order not to block closing a study with large meshes
231 #ifndef WIN32
232     boost::thread aThread(boost::bind( & deleteMeshDS, _meshDS ));
233 #else
234     pthread_t thread;
235     int result=pthread_create(&thread, NULL, deleteMeshDS, (void*)_meshDS);
236 #endif
237   }
238 }
239
240 //================================================================================
241 /*!
242  * \brief Return true if a mesh with given id exists
243  */
244 //================================================================================
245
246 bool SMESH_Mesh::MeshExists( int meshId ) const
247 {
248   return _document ? bool( _document->GetMesh( meshId )) : false;
249 }
250
251 //================================================================================
252 /*!
253  * \brief Return a mesh by id
254  */
255 //================================================================================
256
257 SMESH_Mesh* SMESH_Mesh::FindMesh( int meshId ) const
258 {
259   if ( _id == meshId )
260     return (SMESH_Mesh*) this;
261
262   if ( StudyContextStruct *aStudyContext = _gen->GetStudyContext())
263   {
264     std::map < int, SMESH_Mesh * >::iterator i_m = aStudyContext->mapMesh.find( meshId );
265     if ( i_m != aStudyContext->mapMesh.end() )
266       return i_m->second;
267   }
268   return NULL;
269 }
270
271 //=============================================================================
272 /*!
273  * \brief Set geometry to be meshed
274  */
275 //=============================================================================
276
277 void SMESH_Mesh::ShapeToMesh(const TopoDS_Shape & aShape)
278 {
279   if(MYDEBUG) MESSAGE("SMESH_Mesh::ShapeToMesh");
280
281   if ( !aShape.IsNull() && _isShapeToMesh ) {
282     if ( aShape.ShapeType() != TopAbs_COMPOUND && // group contents is allowed to change
283          _meshDS->ShapeToMesh().ShapeType() != TopAbs_COMPOUND )
284       throw SALOME_Exception(LOCALIZED ("a shape to mesh has already been defined"));
285   }
286   // clear current data
287   if ( !_meshDS->ShapeToMesh().IsNull() )
288   {
289     // removal of a shape to mesh, delete objects referring to sub-shapes:
290     // - sub-meshes
291     _subMeshHolder->DeleteAll();
292     //  - groups on geometry
293     std::map <int, SMESH_Group *>::iterator i_gr = _mapGroup.begin();
294     while ( i_gr != _mapGroup.end() ) {
295       if ( dynamic_cast<SMESHDS_GroupOnGeom*>( i_gr->second->GetGroupDS() )) {
296         _meshDS->RemoveGroup( i_gr->second->GetGroupDS() );
297         delete i_gr->second;
298         _mapGroup.erase( i_gr++ );
299       }
300       else
301         i_gr++;
302     }
303     _mapAncestors.Clear();
304
305     // clear SMESHDS
306     TopoDS_Shape aNullShape;
307     _meshDS->ShapeToMesh( aNullShape );
308
309     _shapeDiagonal = 0.0;
310   }
311
312   // set a new geometry
313   if ( !aShape.IsNull() )
314   {
315     _meshDS->ShapeToMesh(aShape);
316     _isShapeToMesh = true;
317     _nbSubShapes = _meshDS->MaxShapeIndex();
318
319     // fill map of ancestors
320     fillAncestorsMap(aShape);
321   }
322   else
323   {
324     _isShapeToMesh = false;
325     _shapeDiagonal = 0.0;
326     _meshDS->ShapeToMesh( PseudoShape() );
327   }
328   _isModified = false;
329 }
330
331 //=======================================================================
332 /*!
333  * \brief Return geometry to be meshed. (It may be a PseudoShape()!)
334  */
335 //=======================================================================
336
337 TopoDS_Shape SMESH_Mesh::GetShapeToMesh() const
338 {
339   return _meshDS->ShapeToMesh();
340 }
341
342 //=======================================================================
343 /*!
344  * \brief Return a solid which is returned by GetShapeToMesh() if
345  *        a real geometry to be meshed was not set
346  */
347 //=======================================================================
348
349 const TopoDS_Solid& SMESH_Mesh::PseudoShape()
350 {
351   static TopoDS_Solid aSolid;
352   if ( aSolid.IsNull() )
353   {
354     aSolid = BRepPrimAPI_MakeBox(1,1,1);
355   }
356   return aSolid;
357 }
358
359 //=======================================================================
360 /*!
361  * \brief Return diagonal size of bounding box of a shape
362  */
363 //=======================================================================
364
365 double SMESH_Mesh::GetShapeDiagonalSize(const TopoDS_Shape & aShape)
366 {
367   if ( !aShape.IsNull() ) {
368     Bnd_Box Box;
369     // avoid too long waiting on large shapes. PreciseBoundingBox() was added
370     // to assure same result which else depends on presence of triangulation (IPAL52557).
371     const int maxNbFaces = 4000;
372     int nbFaces = 0;
373     for ( TopExp_Explorer f( aShape, TopAbs_FACE ); f.More() && nbFaces < maxNbFaces; f.Next() )
374       ++nbFaces;
375     bool isPrecise = false;
376     if ( nbFaces < maxNbFaces )
377       try {
378         OCC_CATCH_SIGNALS;
379         GEOMUtils::PreciseBoundingBox( aShape, Box );
380         isPrecise = true;
381       }
382       catch (...) {
383         isPrecise = false;
384       }
385     if ( !isPrecise )
386     {
387       BRepBndLib::Add( aShape, Box );
388     }
389     if ( !Box.IsVoid() )
390       return sqrt( Box.SquareExtent() );
391   }
392   return 0;
393 }
394
395 //=======================================================================
396 /*!
397  * \brief Return diagonal size of bounding box of shape to mesh
398  */
399 //=======================================================================
400
401 double SMESH_Mesh::GetShapeDiagonalSize() const
402 {
403   if ( _shapeDiagonal == 0. && _isShapeToMesh )
404     const_cast<SMESH_Mesh*>(this)->_shapeDiagonal = GetShapeDiagonalSize( GetShapeToMesh() );
405
406   return _shapeDiagonal;
407 }
408
409 //================================================================================
410 /*!
411  * \brief Load mesh from study file
412  */
413 //================================================================================
414
415 void SMESH_Mesh::Load()
416 {
417   if (_callUp)
418     _callUp->Load();
419 }
420
421 //=======================================================================
422 /*!
423  * \brief Remove all nodes and elements
424  */
425 //=======================================================================
426
427 void SMESH_Mesh::Clear()
428 {
429   if ( HasShapeToMesh() ) // remove all nodes and elements
430   {
431     // clear mesh data
432     _meshDS->ClearMesh();
433
434     // update compute state of submeshes
435     if ( SMESH_subMesh *sm = GetSubMeshContaining( GetShapeToMesh() ) )
436     {
437       sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
438       sm->ComputeSubMeshStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
439       sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); // for event listeners (issue 0020918)
440       sm->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN );
441     }
442   }
443   else // remove only nodes/elements computed by algorithms
444   {
445     if ( SMESH_subMesh *sm = GetSubMeshContaining( GetShapeToMesh() ) )
446     {
447       sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
448       sm->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN );
449       sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
450       sm->ComputeSubMeshStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
451     }
452   }
453   GetMeshDS()->Modified();
454   _isModified = false;
455 }
456
457 //=======================================================================
458 /*!
459  * \brief Remove all nodes and elements of indicated shape
460  */
461 //=======================================================================
462
463 void SMESH_Mesh::ClearSubMesh(const int theShapeId)
464 {
465   // clear sub-meshes; get ready to re-compute as a side-effect
466   if ( SMESH_subMesh *sm = GetSubMeshContaining( theShapeId ) )
467   {
468     SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true,
469                                                              /*complexShapeFirst=*/false);
470     while ( smIt->more() )
471     {
472       sm = smIt->next();
473       TopAbs_ShapeEnum shapeType = sm->GetSubShape().ShapeType();
474       if ( shapeType == TopAbs_VERTEX || shapeType < TopAbs_SOLID )
475         // all other shapes depends on vertices so they are already cleaned
476         sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
477       // to recompute even if failed
478       sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
479     }
480   }
481 }
482
483 //=======================================================================
484 //function : UNVToMesh
485 //purpose  :
486 //=======================================================================
487
488 int SMESH_Mesh::UNVToMesh(const char* theFileName)
489 {
490   if ( _isShapeToMesh )
491     throw SALOME_Exception(LOCALIZED("a shape to mesh has already been defined"));
492   _isShapeToMesh = false;
493
494   DriverUNV_R_SMDS_Mesh myReader;
495   myReader.SetMesh(_meshDS);
496   myReader.SetFile(theFileName);
497   myReader.SetMeshId(-1);
498   myReader.Perform();
499
500   TGroupNamesMap& aGroupNames = myReader.GetGroupNamesMap();
501   TGroupNamesMap::iterator gr2names;
502   int anId = 1 + ( _mapGroup.empty() ? 0 : _mapGroup.rbegin()->first );
503   for ( gr2names = aGroupNames.begin(); gr2names != aGroupNames.end(); ++gr2names )
504   {
505     SMDS_MeshGroup*   aGroup = gr2names->first;
506     const std::string& aName = gr2names->second;
507     SMESHDS_Group* aGroupDS = new SMESHDS_Group( anId++, _meshDS, aGroup->GetType() );
508     aGroupDS->SMDSGroup() = std::move( *aGroup );
509     aGroupDS->SetStoreName( aName.c_str() );
510     AddGroup( aGroupDS );
511   }
512
513   return 1;
514 }
515
516 //=======================================================================
517 //function : MEDToMesh
518 //purpose  :
519 //=======================================================================
520
521 int SMESH_Mesh::MEDToMesh(const char* theFileName, const char* theMeshName)
522 {
523   if ( _isShapeToMesh )
524     throw SALOME_Exception(LOCALIZED("a shape to mesh has already been defined"));
525   _isShapeToMesh = false;
526
527   DriverMED_R_SMESHDS_Mesh myReader;
528   myReader.SetMesh(_meshDS);
529   myReader.SetMeshId(-1);
530   myReader.SetFile(theFileName);
531   myReader.SetMeshName(theMeshName);
532   Driver_Mesh::Status status = myReader.Perform();
533 #ifdef _DEBUG_
534   SMESH_ComputeErrorPtr er = myReader.GetError();
535   if ( er && !er->IsOK() ) std::cout << er->myComment << std::endl;
536 #endif
537
538   // Reading groups (sub-meshes are out of scope of MED import functionality)
539   std::list<TNameAndType> aGroupNames = myReader.GetGroupNamesAndTypes();
540   std::list<TNameAndType>::iterator name_type = aGroupNames.begin();
541   for ( ; name_type != aGroupNames.end(); name_type++ )
542   {
543     SMESH_Group* aGroup = AddGroup( name_type->second, name_type->first.c_str() );
544     if ( aGroup ) {
545       SMESHDS_Group* aGroupDS = dynamic_cast<SMESHDS_Group*>( aGroup->GetGroupDS() );
546       if ( aGroupDS ) {
547         aGroupDS->SetStoreName( name_type->first.c_str() );
548         myReader.GetGroup( aGroupDS );
549       }
550     }
551   }
552
553   _meshDS->Modified();
554   _meshDS->CompactMesh();
555
556   return (int) status;
557 }
558
559 //=======================================================================
560 //function : STLToMesh
561 //purpose  :
562 //=======================================================================
563
564 std::string SMESH_Mesh::STLToMesh(const char* theFileName)
565 {
566   if(_isShapeToMesh)
567     throw SALOME_Exception(LOCALIZED("a shape to mesh has already been defined"));
568   _isShapeToMesh = false;
569
570   DriverSTL_R_SMDS_Mesh myReader;
571   myReader.SetMesh(_meshDS);
572   myReader.SetFile(theFileName);
573   myReader.SetMeshId(-1);
574   myReader.Perform();
575
576   return myReader.GetName();
577 }
578
579 //================================================================================
580 /*!
581  * \brief Reads the given mesh from the CGNS file
582  *  \param theFileName - name of the file
583  *  \retval int - Driver_Mesh::Status
584  */
585 //================================================================================
586
587 int SMESH_Mesh::CGNSToMesh(const char*  theFileName,
588                            const int    theMeshIndex,
589                            std::string& theMeshName)
590 {
591   int res = Driver_Mesh::DRS_FAIL;
592 #ifdef WITH_CGNS
593
594   DriverCGNS_Read myReader;
595   myReader.SetMesh(_meshDS);
596   myReader.SetFile(theFileName);
597   myReader.SetMeshId(theMeshIndex);
598   res = myReader.Perform();
599   theMeshName = myReader.GetMeshName();
600
601   // create groups
602   SynchronizeGroups();
603
604 #endif
605   return res;
606 }
607
608 //================================================================================
609 /*!
610  * \brief Fill its data by reading a GMF file
611  */
612 //================================================================================
613
614 SMESH_ComputeErrorPtr SMESH_Mesh::GMFToMesh(const char* theFileName,
615                                             bool        theMakeRequiredGroups)
616 {
617   DriverGMF_Read myReader;
618   myReader.SetMesh(_meshDS);
619   myReader.SetFile(theFileName);
620   myReader.SetMakeRequiredGroups( theMakeRequiredGroups );
621   myReader.Perform();
622   //theMeshName = myReader.GetMeshName();
623
624   // create groups
625   SynchronizeGroups();
626
627   return myReader.GetError();
628 }
629
630 //=============================================================================
631 /*!
632  * 
633  */
634 //=============================================================================
635
636 SMESH_Hypothesis::Hypothesis_Status
637 SMESH_Mesh::AddHypothesis(const TopoDS_Shape & aSubShape,
638                           int                  anHypId,
639                           std::string*         anError  )
640 {
641   if(MYDEBUG) MESSAGE("SMESH_Mesh::AddHypothesis");
642
643   if ( anError )
644     anError->clear();
645
646   SMESH_subMesh *subMesh = GetSubMesh(aSubShape);
647   if ( !subMesh || !subMesh->GetId())
648     return SMESH_Hypothesis::HYP_BAD_SUBSHAPE;
649
650   SMESH_Hypothesis *anHyp = GetHypothesis( anHypId );
651   if ( !anHyp )
652     throw SALOME_Exception(LOCALIZED("hypothesis does not exist"));
653
654   bool isGlobalHyp = IsMainShape( aSubShape );
655
656   // NotConformAllowed can be only global
657   if ( !isGlobalHyp )
658   {
659     // NOTE: this is not a correct way to check a name of hypothesis,
660     // there should be an attribute of hypothesis saying that it can/can't
661     // be global/local
662     std::string hypName = anHyp->GetName();
663     if ( hypName == "NotConformAllowed" )
664     {
665       if(MYDEBUG) MESSAGE( "Hypothesis <NotConformAllowed> can be only global" );
666       return SMESH_Hypothesis::HYP_INCOMPATIBLE;
667     }
668   }
669
670   // shape
671
672   bool                     isAlgo = ( anHyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO );
673   SMESH_subMesh::algo_event event = isAlgo ? SMESH_subMesh::ADD_ALGO : SMESH_subMesh::ADD_HYP;
674
675   SMESH_Hypothesis::Hypothesis_Status ret = subMesh->AlgoStateEngine(event, anHyp);
676
677   if ( anError && SMESH_Hypothesis::IsStatusFatal(ret) && subMesh->GetComputeError() )
678     *anError = subMesh->GetComputeError()->myComment;
679
680   // sub-shapes
681   if ( !SMESH_Hypothesis::IsStatusFatal(ret) &&
682        anHyp->GetDim() <= SMESH_Gen::GetShapeDim(aSubShape)) // is added on father
683   {
684     event = isAlgo ? SMESH_subMesh::ADD_FATHER_ALGO : SMESH_subMesh::ADD_FATHER_HYP;
685
686     SMESH_Hypothesis::Hypothesis_Status ret2 =
687       subMesh->SubMeshesAlgoStateEngine(event, anHyp, /*exitOnFatal=*/true);
688     if (ret2 > ret)
689     {
690       ret = ret2;
691       if ( SMESH_Hypothesis::IsStatusFatal( ret ))
692       {
693         if ( anError && subMesh->GetComputeError() )
694           *anError = subMesh->GetComputeError()->myComment;
695         // remove anHyp
696         event = isAlgo ? SMESH_subMesh::REMOVE_ALGO : SMESH_subMesh::REMOVE_HYP;
697         subMesh->AlgoStateEngine(event, anHyp);
698       }
699     }
700
701     // check concurrent hypotheses on ancestors
702     if (ret < SMESH_Hypothesis::HYP_CONCURRENT && !isGlobalHyp )
703     {
704       SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(false,false);
705       while ( smIt->more() ) {
706         SMESH_subMesh* sm = smIt->next();
707         if ( sm->IsApplicableHypothesis( anHyp )) {
708           ret2 = sm->CheckConcurrentHypothesis( anHyp->GetType() );
709           if (ret2 > ret) {
710             ret = ret2;
711             break;
712           }
713         }
714       }
715     }
716   }
717   HasModificationsToDiscard(); // to reset _isModified flag if a mesh becomes empty
718   GetMeshDS()->Modified();
719
720   if(MYDEBUG) subMesh->DumpAlgoState(true);
721   if(MYDEBUG) SCRUTE(ret);
722   return ret;
723 }
724
725 //=============================================================================
726 /*!
727  * 
728  */
729 //=============================================================================
730
731 SMESH_Hypothesis::Hypothesis_Status
732 SMESH_Mesh::RemoveHypothesis(const TopoDS_Shape & aSubShape,
733                              int                    anHypId)
734 {
735   if(MYDEBUG) MESSAGE("SMESH_Mesh::RemoveHypothesis");
736
737   StudyContextStruct *sc = _gen->GetStudyContext();
738   if (sc->mapHypothesis.find(anHypId) == sc->mapHypothesis.end())
739     throw SALOME_Exception(LOCALIZED("hypothesis does not exist"));
740
741   SMESH_Hypothesis *anHyp = sc->mapHypothesis[anHypId];
742   if(MYDEBUG) { SCRUTE(anHyp->GetType()); }
743
744   // shape 
745
746   bool                     isAlgo = ( !anHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO );
747   SMESH_subMesh::algo_event event = isAlgo ? SMESH_subMesh::REMOVE_ALGO : SMESH_subMesh::REMOVE_HYP;
748
749   SMESH_subMesh *subMesh = GetSubMesh(aSubShape);
750
751   SMESH_Hypothesis::Hypothesis_Status ret = subMesh->AlgoStateEngine(event, anHyp);
752
753   // there may appear concurrent hyps that were covered by the removed hyp
754   if (ret < SMESH_Hypothesis::HYP_CONCURRENT &&
755       subMesh->IsApplicableHypothesis( anHyp ) &&
756       subMesh->CheckConcurrentHypothesis( anHyp->GetType() ) != SMESH_Hypothesis::HYP_OK)
757     ret = SMESH_Hypothesis::HYP_CONCURRENT;
758
759   // sub-shapes
760   if (!SMESH_Hypothesis::IsStatusFatal(ret) &&
761       anHyp->GetDim() <= SMESH_Gen::GetShapeDim(aSubShape)) // is removed from father
762   {
763     event = isAlgo ? SMESH_subMesh::REMOVE_FATHER_ALGO : SMESH_subMesh::REMOVE_FATHER_HYP;
764
765     SMESH_Hypothesis::Hypothesis_Status ret2 =
766       subMesh->SubMeshesAlgoStateEngine(event, anHyp);
767     if (ret2 > ret) // more severe
768       ret = ret2;
769
770     // check concurrent hypotheses on ancestors
771     if (ret < SMESH_Hypothesis::HYP_CONCURRENT && !IsMainShape( aSubShape ) )
772     {
773       SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(false,false);
774       while ( smIt->more() ) {
775         SMESH_subMesh* sm = smIt->next();
776         if ( sm->IsApplicableHypothesis( anHyp )) {
777           ret2 = sm->CheckConcurrentHypothesis( anHyp->GetType() );
778           if (ret2 > ret) {
779             ret = ret2;
780             break;
781           }
782         }
783       }
784     }
785   }
786
787   HasModificationsToDiscard(); // to reset _isModified flag if mesh become empty
788   GetMeshDS()->Modified();
789
790   if(MYDEBUG) subMesh->DumpAlgoState(true);
791   if(MYDEBUG) SCRUTE(ret);
792   return ret;
793 }
794
795 //=============================================================================
796 /*!
797  * 
798  */
799 //=============================================================================
800
801 const std::list<const SMESHDS_Hypothesis*>&
802 SMESH_Mesh::GetHypothesisList(const TopoDS_Shape & aSubShape) const
803 {
804   return _meshDS->GetHypothesis(aSubShape);
805 }
806
807 //=======================================================================
808 /*!
809  * \brief Return the hypothesis assigned to the shape
810  *  \param aSubShape    - the shape to check
811  *  \param aFilter      - the hypothesis filter
812  *  \param andAncestors - flag to check hypos assigned to ancestors of the shape
813  *  \param assignedTo   - to return the shape the found hypo is assigned to
814  *  \retval SMESH_Hypothesis* - the first hypo passed through aFilter
815  */
816 //=======================================================================
817
818 const SMESH_Hypothesis * SMESH_Mesh::GetHypothesis(const TopoDS_Shape &    aSubShape,
819                                                    const SMESH_HypoFilter& aFilter,
820                                                    const bool              andAncestors,
821                                                    TopoDS_Shape*           assignedTo) const
822 {
823   return GetHypothesis( const_cast< SMESH_Mesh* >(this)->GetSubMesh( aSubShape ),
824                         aFilter, andAncestors, assignedTo );
825 }
826
827 //=======================================================================
828 /*!
829  * \brief Return the hypothesis assigned to the shape of a sub-mesh
830  *  \param aSubMesh     - the sub-mesh to check
831  *  \param aFilter      - the hypothesis filter
832  *  \param andAncestors - flag to check hypos assigned to ancestors of the shape
833  *  \param assignedTo   - to return the shape the found hypo is assigned to
834  *  \retval SMESH_Hypothesis* - the first hypo passed through aFilter
835  */
836 //=======================================================================
837
838 const SMESH_Hypothesis * SMESH_Mesh::GetHypothesis(const SMESH_subMesh *   aSubMesh,
839                                                    const SMESH_HypoFilter& aFilter,
840                                                    const bool              andAncestors,
841                                                    TopoDS_Shape*           assignedTo) const
842 {
843   if ( !aSubMesh ) return 0;
844
845   {
846     const TopoDS_Shape & aSubShape = aSubMesh->GetSubShape();
847     const std::list<const SMESHDS_Hypothesis*>& hypList = _meshDS->GetHypothesis(aSubShape);
848     std::list<const SMESHDS_Hypothesis*>::const_iterator hyp = hypList.begin();
849     for ( ; hyp != hypList.end(); hyp++ ) {
850       const SMESH_Hypothesis * h = cSMESH_Hyp( *hyp );
851       if ( aFilter.IsOk( h, aSubShape)) {
852         if ( assignedTo ) *assignedTo = aSubShape;
853         return h;
854       }
855     }
856   }
857   if ( andAncestors )
858   {
859     // user sorted submeshes of ancestors, according to stored submesh priority
860     std::vector< SMESH_subMesh * > & ancestors =
861       const_cast< std::vector< SMESH_subMesh * > & > ( aSubMesh->GetAncestors() );
862     SortByMeshOrder( ancestors );
863
864     std::vector<SMESH_subMesh*>::const_iterator smIt = ancestors.begin(); 
865     for ( ; smIt != ancestors.end(); smIt++ )
866     {
867       const TopoDS_Shape& curSh = (*smIt)->GetSubShape();
868       const std::list<const SMESHDS_Hypothesis*>& hypList = _meshDS->GetHypothesis(curSh);
869       std::list<const SMESHDS_Hypothesis*>::const_iterator hyp = hypList.begin();
870       for ( ; hyp != hypList.end(); hyp++ ) {
871         const SMESH_Hypothesis * h = cSMESH_Hyp( *hyp );
872         if (aFilter.IsOk( h, curSh )) {
873           if ( assignedTo ) *assignedTo = curSh;
874           return h;
875         }
876       }
877     }
878   }
879   return 0;
880 }
881
882 //================================================================================
883 /*!
884  * \brief Return hypotheses assigned to the shape
885   * \param aSubShape - the shape to check
886   * \param aFilter - the hypothesis filter
887   * \param aHypList - the list of the found hypotheses
888   * \param andAncestors - flag to check hypos assigned to ancestors of the shape
889   * \retval int - number of unique hypos in aHypList
890  */
891 //================================================================================
892
893 int SMESH_Mesh::GetHypotheses(const TopoDS_Shape &                     aSubShape,
894                               const SMESH_HypoFilter&                  aFilter,
895                               std::list <const SMESHDS_Hypothesis * >& aHypList,
896                               const bool                               andAncestors,
897                               std::list< TopoDS_Shape > *              assignedTo/*=0*/) const
898 {
899   return GetHypotheses( const_cast< SMESH_Mesh* >(this)->GetSubMesh( aSubShape ),
900                         aFilter, aHypList, andAncestors, assignedTo );
901 }
902
903 //================================================================================
904 /*!
905  * \brief Return hypotheses assigned to the shape of a sub-mesh
906   * \param aSubShape - the sub-mesh to check
907   * \param aFilter - the hypothesis filter
908   * \param aHypList - the list of the found hypotheses
909   * \param andAncestors - flag to check hypos assigned to ancestors of the shape
910   * \retval int - number of unique hypos in aHypList
911  */
912 //================================================================================
913
914 int SMESH_Mesh::GetHypotheses(const SMESH_subMesh *                    aSubMesh,
915                               const SMESH_HypoFilter&                  aFilter,
916                               std::list <const SMESHDS_Hypothesis * >& aHypList,
917                               const bool                               andAncestors,
918                               std::list< TopoDS_Shape > *              assignedTo/*=0*/) const
919 {
920   if ( !aSubMesh ) return 0;
921
922   std::set< std::string > hypTypes; // to exclude same type hypos from the result list
923   int nbHyps = 0;
924
925   // only one main hypothesis is allowed
926   bool mainHypFound = false;
927
928   // fill in hypTypes
929   std::list<const SMESHDS_Hypothesis*>::const_iterator hyp;
930   for ( hyp = aHypList.begin(); hyp != aHypList.end(); hyp++ ) {
931     if ( hypTypes.insert( (*hyp)->GetName() ).second )
932       nbHyps++;
933     if ( !cSMESH_Hyp(*hyp)->IsAuxiliary() )
934       mainHypFound = true;
935   }
936
937   // get hypos from aSubShape
938   {
939     const TopoDS_Shape & aSubShape = aSubMesh->GetSubShape();
940     const std::list<const SMESHDS_Hypothesis*>& hypList = _meshDS->GetHypothesis(aSubShape);
941     for ( hyp = hypList.begin(); hyp != hypList.end(); hyp++ )
942     {
943       const SMESH_Hypothesis* h = cSMESH_Hyp( *hyp );
944       if (( aFilter.IsOk( h, aSubShape )) &&
945           ( h->IsAuxiliary() || !mainHypFound ) &&
946           ( h->IsAuxiliary() || hypTypes.insert( h->GetName() ).second ))
947       {
948         aHypList.push_back( *hyp );
949         nbHyps++;
950         if ( !h->IsAuxiliary() )
951           mainHypFound = true;
952         if ( assignedTo ) assignedTo->push_back( aSubShape );
953       }
954     }
955   }
956
957   // get hypos from ancestors of aSubShape
958   if ( andAncestors )
959   {
960     // user sorted submeshes of ancestors, according to stored submesh priority
961     std::vector< SMESH_subMesh * > & ancestors =
962       const_cast< std::vector< SMESH_subMesh * > & > ( aSubMesh->GetAncestors() );
963     SortByMeshOrder( ancestors );
964
965     std::vector<SMESH_subMesh*>::const_iterator smIt = ancestors.begin();
966     for ( ; smIt != ancestors.end(); smIt++ )
967     {
968       const TopoDS_Shape& curSh = (*smIt)->GetSubShape();
969       const std::list<const SMESHDS_Hypothesis*>& hypList = _meshDS->GetHypothesis(curSh);
970       for ( hyp = hypList.begin(); hyp != hypList.end(); hyp++ )
971       {
972         const SMESH_Hypothesis* h = cSMESH_Hyp( *hyp );
973         if (( aFilter.IsOk( h, curSh )) &&
974             ( h->IsAuxiliary() || !mainHypFound ) &&
975             ( h->IsAuxiliary() || hypTypes.insert( h->GetName() ).second ))
976         {
977           aHypList.push_back( *hyp );
978           nbHyps++;
979           if ( !h->IsAuxiliary() )
980             mainHypFound = true;
981           if ( assignedTo ) assignedTo->push_back( curSh );
982         }
983       }
984     }
985   }
986   return nbHyps;
987 }
988
989 //================================================================================
990 /*!
991  * \brief Return a hypothesis by its ID
992  */
993 //================================================================================
994
995 SMESH_Hypothesis * SMESH_Mesh::GetHypothesis(const int anHypId) const
996 {
997   StudyContextStruct *sc = _gen->GetStudyContext();
998   if (sc->mapHypothesis.find(anHypId) == sc->mapHypothesis.end())
999     return NULL;
1000
1001   SMESH_Hypothesis *anHyp = sc->mapHypothesis[anHypId];
1002   return anHyp;
1003 }
1004
1005 //=============================================================================
1006 /*!
1007  * 
1008  */
1009 //=============================================================================
1010
1011 const std::list<SMESHDS_Command*> & SMESH_Mesh::GetLog()
1012 {
1013   return _meshDS->GetScript()->GetCommands();
1014 }
1015
1016 //=============================================================================
1017 /*!
1018  * 
1019  */
1020 //=============================================================================
1021 void SMESH_Mesh::ClearLog()
1022 {
1023   _meshDS->GetScript()->Clear();
1024 }
1025
1026 //=============================================================================
1027 /*!
1028  * Get or Create the SMESH_subMesh object implementation
1029  */
1030 //=============================================================================
1031
1032 SMESH_subMesh * SMESH_Mesh::GetSubMesh(const TopoDS_Shape & aSubShape)
1033 {
1034   int index = _meshDS->ShapeToIndex(aSubShape);
1035   if ( !index && aSubShape.IsNull() )
1036     return 0;
1037
1038   // for submeshes on GEOM Group
1039   if (( !index || index > _nbSubShapes ) && aSubShape.ShapeType() == TopAbs_COMPOUND )
1040   {
1041     TopoDS_Iterator it( aSubShape );
1042     if ( it.More() )
1043     {
1044       index = _meshDS->AddCompoundSubmesh( aSubShape, it.Value().ShapeType() );
1045       // fill map of Ancestors
1046       while ( _nbSubShapes < index )
1047         fillAncestorsMap( _meshDS->IndexToShape( ++_nbSubShapes ));
1048     }
1049   }
1050   // if ( !index )
1051   //   return NULL; // neither sub-shape nor a group
1052
1053   SMESH_subMesh* aSubMesh = _subMeshHolder->Get( index );
1054   if ( !aSubMesh )
1055   {
1056     aSubMesh = new SMESH_subMesh(index, this, _meshDS, aSubShape);
1057     _subMeshHolder->Add( index, aSubMesh );
1058
1059     // include non-computable sub-meshes in SMESH_subMesh::_ancestors of sub-submeshes
1060     switch ( aSubShape.ShapeType() ) {
1061     case TopAbs_COMPOUND:
1062     case TopAbs_WIRE:
1063     case TopAbs_SHELL:
1064       for ( TopoDS_Iterator subIt( aSubShape ); subIt.More(); subIt.Next() )
1065       {
1066         SMESH_subMesh* sm = GetSubMesh( subIt.Value() );
1067         SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*inclideSelf=*/true);
1068         while ( smIt->more() )
1069           smIt->next()->ClearAncestors();
1070       }
1071     default:;
1072     }
1073   }
1074   return aSubMesh;
1075 }
1076
1077 //=============================================================================
1078 /*!
1079  * Get the SMESH_subMesh object implementation. Don't create it, return null
1080  * if it does not exist.
1081  */
1082 //=============================================================================
1083
1084 SMESH_subMesh *SMESH_Mesh::GetSubMeshContaining(const TopoDS_Shape & aSubShape) const
1085 {
1086   int index = _meshDS->ShapeToIndex(aSubShape);
1087   return GetSubMeshContaining( index );
1088 }
1089
1090 //=============================================================================
1091 /*!
1092  * Get the SMESH_subMesh object implementation. Don't create it, return null
1093  * if it does not exist.
1094  */
1095 //=============================================================================
1096
1097 SMESH_subMesh *SMESH_Mesh::GetSubMeshContaining(const int aShapeID) const
1098 {
1099   SMESH_subMesh *aSubMesh = _subMeshHolder->Get( aShapeID );
1100   return aSubMesh;
1101 }
1102
1103 //================================================================================
1104 /*!
1105  * \brief Return sub-meshes of groups containing the given sub-shape
1106  */
1107 //================================================================================
1108
1109 std::list<SMESH_subMesh*>
1110 SMESH_Mesh::GetGroupSubMeshesContaining(const TopoDS_Shape & aSubShape) const
1111 {
1112   std::list<SMESH_subMesh*> found;
1113
1114   SMESH_subMesh * subMesh = GetSubMeshContaining(aSubShape);
1115   if ( !subMesh )
1116     return found;
1117
1118   // sub-meshes of groups have max IDs, so search from the map end
1119   SMESH_subMeshIteratorPtr smIt( _subMeshHolder->GetIterator( /*reverse=*/true ) );
1120   while ( smIt->more() ) {
1121     SMESH_subMesh*    sm = smIt->next();
1122     SMESHDS_SubMesh * ds = sm->GetSubMeshDS();
1123     if ( ds && ds->IsComplexSubmesh() ) {
1124       if ( SMESH_MesherHelper::IsSubShape( aSubShape, sm->GetSubShape() ))
1125       {
1126         found.push_back( sm );
1127         //break;
1128       }
1129     } else {
1130       break; // the rest sub-meshes are not those of groups
1131     }
1132   }
1133
1134   if ( found.empty() ) // maybe the main shape is a COMPOUND (issue 0021530)
1135   {
1136     if ( SMESH_subMesh * mainSM = GetSubMeshContaining(1) )
1137       if ( mainSM->GetSubShape().ShapeType() == TopAbs_COMPOUND )
1138       {
1139         TopoDS_Iterator it( mainSM->GetSubShape() );
1140         if ( it.Value().ShapeType() == aSubShape.ShapeType() &&
1141              SMESH_MesherHelper::IsSubShape( aSubShape, mainSM->GetSubShape() ))
1142           found.push_back( mainSM );
1143       }
1144   }
1145   else // issue 0023068
1146   {
1147     if ( SMESH_subMesh * mainSM = GetSubMeshContaining(1) )
1148       if ( mainSM->GetSubShape().ShapeType() == TopAbs_COMPOUND )
1149         found.push_back( mainSM );
1150   }
1151   return found;
1152 }
1153 //=======================================================================
1154 //function : IsUsedHypothesis
1155 //purpose  : Return True if anHyp is used to mesh aSubShape
1156 //=======================================================================
1157
1158 bool SMESH_Mesh::IsUsedHypothesis(SMESHDS_Hypothesis * anHyp,
1159                                   const SMESH_subMesh* aSubMesh)
1160 {
1161   SMESH_Hypothesis* hyp = static_cast<SMESH_Hypothesis*>(anHyp);
1162
1163   // check if anHyp can be used to mesh aSubMesh
1164   if ( !aSubMesh || !aSubMesh->IsApplicableHypothesis( hyp ))
1165     return false;
1166
1167   SMESH_Algo *algo = aSubMesh->GetAlgo();
1168
1169   // algorithm
1170   if (anHyp->GetType() > SMESHDS_Hypothesis::PARAM_ALGO)
1171     return ( anHyp == algo );
1172
1173   // algorithm parameter
1174   if (algo)
1175   {
1176     // look through hypotheses used by algo
1177     const SMESH_HypoFilter* hypoKind;
1178     if (( hypoKind = algo->GetCompatibleHypoFilter( !hyp->IsAuxiliary() ))) {
1179       std::list <const SMESHDS_Hypothesis * > usedHyps;
1180       if ( GetHypotheses( aSubMesh, *hypoKind, usedHyps, true ))
1181         return ( find( usedHyps.begin(), usedHyps.end(), anHyp ) != usedHyps.end() );
1182     }
1183   }
1184
1185   return false;
1186 }
1187
1188 //=======================================================================
1189 //function : NotifySubMeshesHypothesisModification
1190 //purpose  : Say all submeshes using theChangedHyp that it has been modified
1191 //=======================================================================
1192
1193 void SMESH_Mesh::NotifySubMeshesHypothesisModification(const SMESH_Hypothesis* hyp)
1194 {
1195
1196   if ( !GetMeshDS()->IsUsedHypothesis( hyp ))
1197     return;
1198
1199   smIdType nbEntities = ( _meshDS->NbNodes() + _meshDS->NbElements() );
1200   if ( hyp && _callUp && !_callUp->IsLoaded() ) // for not loaded mesh (#16648)
1201   {
1202     _callUp->HypothesisModified( hyp->GetID(), /*updateIcons=*/true );
1203     nbEntities = ( _meshDS->NbNodes() + _meshDS->NbElements() ); // after loading mesh
1204   }
1205
1206   SMESH_Algo *algo;
1207   const SMESH_HypoFilter* compatibleHypoKind;
1208   std::list <const SMESHDS_Hypothesis * > usedHyps;
1209   std::vector< SMESH_subMesh* > smToNotify;
1210   bool allMeshedEdgesNotified = true;
1211
1212   SMESH_subMeshIteratorPtr smIt( _subMeshHolder->GetIterator() );
1213   while ( smIt->more() )
1214   {
1215     SMESH_subMesh* aSubMesh = smIt->next();
1216     bool toNotify = false;
1217
1218     // if aSubMesh meshing depends on hyp,
1219     // we call aSubMesh->AlgoStateEngine( MODIF_HYP, hyp ) that causes either
1220     // 1) clearing already computed aSubMesh or
1221     // 2) changing algo_state from MISSING_HYP to HYP_OK when parameters of hyp becomes valid,
1222     // other possible changes are not interesting. (IPAL0052457 - assigning hyp performance pb)
1223     if ( aSubMesh->GetComputeState() == SMESH_subMesh::COMPUTE_OK ||
1224          aSubMesh->GetComputeState() == SMESH_subMesh::FAILED_TO_COMPUTE ||
1225          aSubMesh->GetAlgoState()    == SMESH_subMesh::MISSING_HYP ||
1226          hyp->DataDependOnParams() )
1227     {
1228       const TopoDS_Shape & aSubShape = aSubMesh->GetSubShape();
1229
1230       if (( aSubMesh->IsApplicableHypothesis( hyp )) &&
1231           ( algo = aSubMesh->GetAlgo() )            &&
1232           ( compatibleHypoKind = algo->GetCompatibleHypoFilter( !hyp->IsAuxiliary() )) &&
1233           ( compatibleHypoKind->IsOk( hyp, aSubShape )))
1234       {
1235         // check if hyp is used by algo
1236         usedHyps.clear();
1237         toNotify = ( GetHypotheses( aSubMesh, *compatibleHypoKind, usedHyps, true ) &&
1238                      std::find( usedHyps.begin(), usedHyps.end(), hyp ) != usedHyps.end() );
1239       }
1240     }
1241     if ( toNotify )
1242     {
1243       smToNotify.push_back( aSubMesh );
1244       if ( aSubMesh->GetAlgoState() == SMESH_subMesh::MISSING_HYP )
1245         allMeshedEdgesNotified = false; //  update of algo state needed, not mesh clearing
1246     }
1247     else
1248     {
1249       if ( !aSubMesh->IsEmpty() &&
1250            aSubMesh->GetSubShape().ShapeType() == TopAbs_EDGE )
1251         allMeshedEdgesNotified = false;
1252     }
1253   }
1254   if ( smToNotify.empty() )
1255     return;
1256
1257   // if all meshed EDGEs will be notified then the notification is equivalent
1258   // to the whole mesh clearing, which is usually faster
1259   if ( allMeshedEdgesNotified && NbNodes() > 0 )
1260   {
1261     Clear();
1262   }
1263   else
1264   {
1265     // notify in reverse order to avoid filling the pool of IDs
1266     for ( int i = smToNotify.size()-1; i >= 0; --i )
1267       smToNotify[i]->AlgoStateEngine(SMESH_subMesh::MODIF_HYP,
1268                                      const_cast< SMESH_Hypothesis*>( hyp ));
1269   }
1270   HasModificationsToDiscard(); // to reset _isModified flag if mesh becomes empty
1271   GetMeshDS()->Modified();
1272
1273   smIdType newNbEntities = ( _meshDS->NbNodes() + _meshDS->NbElements() );
1274   if ( hyp && _callUp )
1275     _callUp->HypothesisModified( hyp->GetID(), newNbEntities != nbEntities );
1276 }
1277
1278 //=============================================================================
1279 /*!
1280  *  Auto color functionality
1281  */
1282 //=============================================================================
1283 void SMESH_Mesh::SetAutoColor(bool theAutoColor)
1284 {
1285   _isAutoColor = theAutoColor;
1286 }
1287
1288 bool SMESH_Mesh::GetAutoColor()
1289 {
1290   return _isAutoColor;
1291 }
1292
1293 //=======================================================================
1294 //function : SetIsModified
1295 //purpose  : Set the flag meaning that the mesh has been edited "manually"
1296 //=======================================================================
1297
1298 void SMESH_Mesh::SetIsModified(bool isModified)
1299 {
1300   _isModified = isModified;
1301
1302   if ( _isModified )
1303     // check if mesh becomes empty as result of modification
1304     HasModificationsToDiscard();
1305 }
1306
1307 //=======================================================================
1308 //function : HasModificationsToDiscard
1309 //purpose  : Return true if the mesh has been edited since a total re-compute
1310 //           and those modifications may prevent successful partial re-compute.
1311 //           As a side effect reset _isModified flag if mesh is empty
1312 //issue    : 0020693
1313 //=======================================================================
1314
1315 bool SMESH_Mesh::HasModificationsToDiscard() const
1316 {
1317   if ( ! _isModified )
1318     return false;
1319
1320   // return true if the next Compute() will be partial and
1321   // existing but changed elements may prevent successful re-compute
1322   bool hasComputed = false, hasNotComputed = false;
1323   SMESH_subMeshIteratorPtr smIt( _subMeshHolder->GetIterator() );
1324   while ( smIt->more() )
1325   {
1326     const SMESH_subMesh* aSubMesh = smIt->next();
1327     switch ( aSubMesh->GetSubShape().ShapeType() )
1328     {
1329     case TopAbs_EDGE:
1330     case TopAbs_FACE:
1331     case TopAbs_SOLID:
1332       if ( aSubMesh->IsMeshComputed() )
1333         hasComputed = true;
1334       else
1335         hasNotComputed = true;
1336       if ( hasComputed && hasNotComputed)
1337         return true;
1338
1339     default:;
1340     }
1341   }
1342   if ( NbNodes() < 1 )
1343     const_cast<SMESH_Mesh*>(this)->_isModified = false;
1344
1345   return false;
1346 }
1347
1348 //=============================================================================
1349 /*!
1350  * \brief Return true if all sub-meshes are computed OK - to update an icon
1351  */
1352 //=============================================================================
1353
1354 bool SMESH_Mesh::IsComputedOK()
1355 {
1356   if ( NbNodes() == 0 )
1357     return false;
1358
1359   // if ( !HasShapeToMesh() )
1360   //   return true;
1361
1362   if ( SMESH_subMesh* mainSM = GetSubMeshContaining( 1 ))
1363   {
1364     SMESH_subMeshIteratorPtr smIt = mainSM->getDependsOnIterator(/*includeSelf=*/true);
1365     while ( smIt->more() )
1366     {
1367       const SMESH_subMesh* sm = smIt->next();
1368       if ( !sm->IsAlwaysComputed() )
1369         switch ( sm->GetComputeState() )
1370         {
1371         case SMESH_subMesh::NOT_READY:
1372         case SMESH_subMesh::COMPUTE_OK:
1373           continue; // ok
1374         case SMESH_subMesh::FAILED_TO_COMPUTE:
1375         case SMESH_subMesh::READY_TO_COMPUTE:
1376           return false;
1377         }
1378     }
1379   }
1380   return true;
1381 }
1382
1383 //================================================================================
1384 /*!
1385  * \brief Check if any groups of the same type have equal names
1386  */
1387 //================================================================================
1388
1389 bool SMESH_Mesh::HasDuplicatedGroupNamesMED()
1390 {
1391   // Corrected for Mantis issue 0020028
1392   std::map< SMDSAbs_ElementType, std::set< std::string > > aGroupNames;
1393   for ( std::map<int, SMESH_Group*>::iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ )
1394   {
1395     SMESH_Group*       aGroup = it->second;
1396     SMDSAbs_ElementType aType = aGroup->GetGroupDS()->GetType();
1397     std::string    aGroupName = aGroup->GetName();
1398     aGroupName.resize( MAX_MED_GROUP_NAME_LENGTH );
1399     if ( !aGroupNames[aType].insert(aGroupName).second )
1400       return true;
1401   }
1402
1403   return false;
1404 }
1405
1406 //================================================================================
1407 /*!
1408  * \brief Export the mesh to a writer
1409  */
1410 //================================================================================
1411
1412 void SMESH_Mesh::exportMEDCommmon(DriverMED_W_SMESHDS_Mesh& theWriter,
1413                                   const char*               theMeshName,
1414                                   bool                      theAutoGroups,
1415                                   const SMESHDS_Mesh*       theMeshPart,
1416                                   bool                      theAutoDimension,
1417                                   bool                      theAddODOnVertices,
1418                                   double                    theZTolerance,
1419                                   bool                      theSaveNumbers,
1420                                   bool                      theAllElemsToGroup)
1421 {
1422   Driver_Mesh::Status status = Driver_Mesh::DRS_OK;
1423
1424   SMESH_TRY;
1425
1426   theWriter.SetMesh         ( theMeshPart ? (SMESHDS_Mesh*) theMeshPart : _meshDS   );
1427   theWriter.SetAutoDimension( theAutoDimension );
1428   theWriter.AddODOnVertices ( theAddODOnVertices );
1429   theWriter.SetZTolerance   ( theZTolerance );
1430   theWriter.SetSaveNumbers  ( theSaveNumbers );
1431   if ( !theMeshName )
1432     theWriter.SetMeshId     ( _id         );
1433   else {
1434     theWriter.SetMeshId     ( -1          );
1435     theWriter.SetMeshName   ( theMeshName );
1436   }
1437
1438   if ( theAutoGroups ) {
1439     theWriter.AddGroupOfNodes();
1440     theWriter.AddGroupOfEdges();
1441     theWriter.AddGroupOfFaces();
1442     theWriter.AddGroupOfVolumes();
1443     theWriter.AddGroupOf0DElems();
1444     theWriter.AddGroupOfBalls();
1445   }
1446   if ( theAllElemsToGroup )
1447     theWriter.AddAllToGroup();
1448
1449   // Pass groups to writer. Provide unique group names.
1450   //set<string> aGroupNames; // Corrected for Mantis issue 0020028
1451   if ( !theMeshPart )
1452   {
1453     std::map< SMDSAbs_ElementType, std::set<std::string> > aGroupNames;
1454     char aString [256];
1455     int maxNbIter = 10000; // to guarantee cycle finish
1456     for ( std::map<int, SMESH_Group*>::iterator it = _mapGroup.begin();
1457           it != _mapGroup.end();
1458           it++ ) {
1459       SMESH_Group*       aGroup   = it->second;
1460       SMESHDS_GroupBase* aGroupDS = aGroup->GetGroupDS();
1461       if ( aGroupDS ) {
1462         SMDSAbs_ElementType aType = aGroupDS->GetType();
1463         std::string aGroupName0 = aGroup->GetName();
1464         aGroupName0.resize(MAX_MED_GROUP_NAME_LENGTH);
1465         std::string aGroupName = aGroupName0;
1466         for (int i = 1; !aGroupNames[aType].insert(aGroupName).second && i < maxNbIter; i++) {
1467           sprintf(&aString[0], "GR_%d_%s", i, aGroupName0.c_str());
1468           aGroupName = aString;
1469           aGroupName.resize(MAX_MED_GROUP_NAME_LENGTH);
1470         }
1471         aGroupDS->SetStoreName( aGroupName.c_str() );
1472         theWriter.AddGroup( aGroupDS );
1473       }
1474     }
1475   }
1476   // Perform export
1477   status = theWriter.Perform();
1478
1479   SMESH_CATCH( SMESH::throwSalomeEx );
1480
1481   if ( status == Driver_Mesh::DRS_TOO_LARGE_MESH )
1482     throw TooLargeForExport("MED");
1483 }
1484
1485 //================================================================================
1486 /*!
1487  * Same as SMESH_Mesh::ExportMED except for \a file and \a theVersion
1488  */
1489 //================================================================================
1490
1491 MEDCoupling::MCAuto<MEDCoupling::DataArrayByte>
1492 SMESH_Mesh::ExportMEDCoupling(const char*         theMeshName,
1493                               bool                theAutoGroups,
1494                               const SMESHDS_Mesh* theMeshPart,
1495                               bool                theAutoDimension,
1496                               bool                theAddODOnVertices,
1497                               double              theZTolerance,
1498                               bool                theSaveNumbers)
1499 {
1500   DriverMED_W_SMESHDS_Mesh_Mem writer;
1501   this->exportMEDCommmon( writer, theMeshName, theAutoGroups, theMeshPart, theAutoDimension,
1502                           theAddODOnVertices, theZTolerance, theSaveNumbers,
1503                           /*AllElemsToGroup(for ExportSAUV())=*/false);
1504   return writer.getData();
1505 }
1506
1507 //================================================================================
1508 /*!
1509  * \brief Export the mesh to a med file
1510  *  \param [in] theFile - name of the MED file
1511  *  \param [in] theMeshName - name of this mesh
1512  *  \param [in] theAutoGroups - boolean parameter for creating/not creating
1513  *              the groups Group_On_All_Nodes, Group_On_All_Faces, ... ;
1514  *              the typical use is auto_groups=false.
1515  *  \param [in] theVersion - define the minor (xy, where version is x.y.z) of MED file format.
1516  *              If theVersion is equal to -1, the minor version is not changed (default).
1517  *  \param [in] theMeshPart - mesh data to export
1518  *  \param [in] theAutoDimension - if \c true, a space dimension of a MED mesh can be either
1519  *              - 1D if all mesh nodes lie on OX coordinate axis, or
1520  *              - 2D if all mesh nodes lie on XOY coordinate plane, or
1521  *              - 3D in the rest cases.
1522  *              If \a theAutoDimension is \c false, the space dimension is always 3.
1523  *  \param [in] theAddODOnVertices - to create 0D elements on all vertices
1524  *  \param [in] theZTolerance - tolerance in Z direction. If Z coordinate of a node is close to zero
1525  *              within a given tolerance, the coordinate is set to zero.
1526  *              If \a ZTolerance is negative, the node coordinates are kept as is.
1527  *  \param [in] theSaveNumbers : enable saving numbers of nodes and cells.
1528  *  \param [in] theAllElemsToGroup - to make every element to belong to any group (PAL23413).
1529  *              It is used by ExportSAUV() only
1530  *  \return int - mesh index in the file
1531  */
1532 //================================================================================
1533
1534 void SMESH_Mesh::ExportMED(const char *        theFile,
1535                            const char*         theMeshName,
1536                            bool                theAutoGroups,
1537                            int                 theVersion,
1538                            const SMESHDS_Mesh* theMeshPart,
1539                            bool                theAutoDimension,
1540                            bool                theAddODOnVertices,
1541                            double              theZTolerance,
1542                            bool                theSaveNumbers,
1543                            bool                theAllElemsToGroup)
1544 {
1545   MESSAGE("MED_VERSION:"<< theVersion);
1546   DriverMED_W_SMESHDS_Mesh writer;
1547   writer.SetFile( theFile, theVersion );
1548   this->exportMEDCommmon( writer, theMeshName, theAutoGroups, theMeshPart, theAutoDimension, theAddODOnVertices, theZTolerance, theSaveNumbers, theAllElemsToGroup );
1549 }
1550
1551 //================================================================================
1552 /*!
1553  * \brief Export the mesh to a SAUV file
1554  */
1555 //================================================================================
1556
1557 void SMESH_Mesh::ExportSAUV(const char *theFile,
1558                             const char* theMeshName,
1559                             bool        theAutoGroups)
1560 {
1561   std::string medfilename( theFile );
1562   medfilename += ".med";
1563   std::string cmd;
1564 #ifdef WIN32
1565   cmd = "%PYTHONBIN% ";
1566 #else
1567   cmd = "python3 ";
1568 #endif
1569   cmd += "-c \"";
1570   cmd += "from medutilities import my_remove ; my_remove(r'" + medfilename + "')";
1571   cmd += "\"";
1572   system(cmd.c_str());
1573   try {
1574     ExportMED( medfilename.c_str(), theMeshName, theAutoGroups, /*minor=*/-1,
1575                /*meshPart=*/NULL, /*theAutoDimension=*/false, /*theAddODOnVertices=*/false,
1576                /*zTol=*/-1, /*theSaveNumbers=*/false,
1577                /*theAllElemsToGroup=*/true ); // theAllElemsToGroup is for PAL0023413
1578   }
1579   catch ( TooLargeForExport )
1580   {
1581     throw TooLargeForExport("SAUV");
1582   }
1583 #ifdef WIN32
1584   cmd = "%PYTHONBIN% ";
1585 #else
1586   cmd = "python3 ";
1587 #endif
1588   cmd += "-c \"";
1589   cmd += "from medutilities import convert ; convert(r'" + medfilename + "', 'MED', 'GIBI', 1, r'" + theFile + "')";
1590   cmd += "\"";
1591   system(cmd.c_str());
1592 #ifdef WIN32
1593   cmd = "%PYTHONBIN% ";
1594 #else
1595   cmd = "python3 ";
1596 #endif
1597   cmd += "-c \"";
1598   cmd += "from medutilities import my_remove ; my_remove(r'" + medfilename + "')";
1599   cmd += "\"";
1600   system(cmd.c_str());
1601 }
1602
1603 //================================================================================
1604 /*!
1605  * \brief Export the mesh to a DAT file
1606  */
1607 //================================================================================
1608
1609 void SMESH_Mesh::ExportDAT(const char *        file,
1610                            const SMESHDS_Mesh* meshPart,
1611                            const bool          renumber)
1612 {
1613   Driver_Mesh::Status status;
1614   SMESH_TRY;
1615
1616   DriverDAT_W_SMDS_Mesh writer;
1617   writer.SetFile( file );
1618   writer.SetMesh( meshPart ? (SMESHDS_Mesh*) meshPart : _meshDS );
1619   writer.SetMeshId(_id);
1620   writer.SetRenumber( renumber );
1621   status = writer.Perform();
1622
1623   SMESH_CATCH( SMESH::throwSalomeEx );
1624
1625   if ( status == Driver_Mesh::DRS_TOO_LARGE_MESH )
1626     throw TooLargeForExport("DAT");
1627 }
1628
1629 //================================================================================
1630 /*!
1631  * \brief Export the mesh to an UNV file
1632  */
1633 //================================================================================
1634
1635 void SMESH_Mesh::ExportUNV(const char *        file,
1636                            const SMESHDS_Mesh* meshPart,
1637                            const bool          renumber)
1638 {
1639   Driver_Mesh::Status status;
1640
1641   SMESH_TRY;
1642   DriverUNV_W_SMDS_Mesh writer;
1643   writer.SetFile( file );
1644   writer.SetMesh( meshPart ? (SMESHDS_Mesh*) meshPart : _meshDS );
1645   writer.SetMeshId(_id);
1646   writer.SetRenumber( renumber );
1647
1648   // pass group names to SMESHDS
1649   if ( !meshPart )
1650   {
1651     std::map<int, SMESH_Group*>::iterator it = _mapGroup.begin();
1652     for ( ; it != _mapGroup.end(); it++ ) {
1653       SMESH_Group*       aGroup   = it->second;
1654       SMESHDS_GroupBase* aGroupDS = aGroup->GetGroupDS();
1655       if ( aGroupDS ) {
1656         std::string aGroupName = aGroup->GetName();
1657         aGroupDS->SetStoreName( aGroupName.c_str() );
1658         writer.AddGroup( aGroupDS );
1659       }
1660     }
1661   }
1662   status = writer.Perform();
1663
1664   SMESH_CATCH( SMESH::throwSalomeEx );
1665
1666   if ( status == Driver_Mesh::DRS_TOO_LARGE_MESH )
1667     throw TooLargeForExport("UNV");
1668 }
1669
1670 //================================================================================
1671 /*!
1672  * \brief Export the mesh to an STL file
1673  */
1674 //================================================================================
1675
1676 void SMESH_Mesh::ExportSTL(const char *        file,
1677                            const bool          isascii,
1678                            const char *        name,
1679                            const SMESHDS_Mesh* meshPart)
1680 {
1681   Driver_Mesh::Status status;
1682   SMESH_TRY;
1683
1684   DriverSTL_W_SMDS_Mesh writer;
1685   writer.SetFile( file );
1686   writer.SetIsAscii( isascii );
1687   writer.SetMesh( meshPart ? (SMESHDS_Mesh*) meshPart : _meshDS);
1688   writer.SetMeshId(_id);
1689   if ( name ) writer.SetName( name );
1690   status = writer.Perform();
1691
1692   SMESH_CATCH( SMESH::throwSalomeEx );
1693
1694   if ( status == Driver_Mesh::DRS_TOO_LARGE_MESH )
1695     throw TooLargeForExport("STL");
1696 }
1697
1698 //================================================================================
1699 /*!
1700  * \brief Export the mesh to the CGNS file
1701  */
1702 //================================================================================
1703
1704 void SMESH_Mesh::ExportCGNS(const char *        file,
1705                             const SMESHDS_Mesh* meshDS,
1706                             const char *        meshName,
1707                             const bool          groupElemsByType)
1708 {
1709
1710   int res = Driver_Mesh::DRS_FAIL;
1711   SMESH_TRY;
1712
1713   // pass group names to SMESHDS
1714   std::map<int, SMESH_Group*>::iterator it = _mapGroup.begin();
1715   for ( ; it != _mapGroup.end(); it++ ) {
1716     SMESH_Group*       group   = it->second;
1717     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
1718     if ( groupDS ) {
1719       std::string groupName = group->GetName();
1720       groupDS->SetStoreName( groupName.c_str() );
1721     }
1722   }
1723 #ifdef WITH_CGNS
1724
1725   DriverCGNS_Write writer;
1726   writer.SetFile( file );
1727   writer.SetMesh( const_cast<SMESHDS_Mesh*>( meshDS ));
1728   writer.SetMeshName( SMESH_Comment("Mesh_") << meshDS->GetPersistentId());
1729   if ( meshName && meshName[0] )
1730     writer.SetMeshName( meshName );
1731   writer.SetElementsByType( groupElemsByType );
1732   res = writer.Perform();
1733   if ( res != Driver_Mesh::DRS_OK )
1734   {
1735     SMESH_ComputeErrorPtr err = writer.GetError();
1736     if ( err && !err->IsOK() && !err->myComment.empty() )
1737       throw SALOME_Exception(("Export failed: " + err->myComment ).c_str() );
1738   }
1739
1740 #endif
1741   SMESH_CATCH( SMESH::throwSalomeEx );
1742
1743   if ( res == Driver_Mesh::DRS_TOO_LARGE_MESH )
1744     throw TooLargeForExport("CGNS");
1745
1746   if ( res != Driver_Mesh::DRS_OK )
1747     throw SALOME_Exception("Export failed");
1748 }
1749
1750 //================================================================================
1751 /*!
1752  * \brief Export the mesh to a GMF file
1753  */
1754 //================================================================================
1755
1756 void SMESH_Mesh::ExportGMF(const char *        file,
1757                            const SMESHDS_Mesh* meshDS,
1758                            bool                withRequiredGroups)
1759 {
1760   Driver_Mesh::Status status;
1761   SMESH_TRY;
1762
1763   DriverGMF_Write writer;
1764   writer.SetFile( file );
1765   writer.SetMesh( const_cast<SMESHDS_Mesh*>( meshDS ));
1766   writer.SetExportRequiredGroups( withRequiredGroups );
1767
1768   status = writer.Perform();
1769
1770   SMESH_CATCH( SMESH::throwSalomeEx );
1771
1772   if ( status == Driver_Mesh::DRS_TOO_LARGE_MESH )
1773     throw TooLargeForExport("GMF");
1774 }
1775
1776 //================================================================================
1777 /*!
1778  * \brief Return a ratio of "compute cost" of computed sub-meshes to the whole
1779  *        "compute cost".
1780  */
1781 //================================================================================
1782
1783 double SMESH_Mesh::GetComputeProgress() const
1784 {
1785   double totalCost = 1e-100, computedCost = 0;
1786   const SMESH_subMesh* curSM = _gen->GetCurrentSubMesh();
1787
1788   // get progress of a current algo
1789   TColStd_MapOfInteger currentSubIds; 
1790   if ( curSM )
1791     if ( SMESH_Algo* algo = curSM->GetAlgo() )
1792     {
1793       int algoNotDoneCost = 0, algoDoneCost = 0;
1794       const std::vector<SMESH_subMesh*>& smToCompute = algo->SubMeshesToCompute();
1795       for ( size_t i = 0; i < smToCompute.size(); ++i )
1796       {
1797         if ( smToCompute[i]->IsEmpty() || smToCompute.size() == 1 )
1798           algoNotDoneCost += smToCompute[i]->GetComputeCost();
1799         else
1800           algoDoneCost += smToCompute[i]->GetComputeCost();
1801         currentSubIds.Add( smToCompute[i]->GetId() );
1802       }
1803       double rate = 0;
1804       try
1805       {
1806         OCC_CATCH_SIGNALS;
1807         rate = algo->GetProgress();
1808       }
1809       catch (...) {
1810 #ifdef _DEBUG_
1811         std::cerr << "Exception in " << algo->GetName() << "::GetProgress()" << std::endl;
1812 #endif
1813       }
1814       if ( 0. < rate && rate < 1.001 )
1815       {
1816         computedCost += rate * ( algoDoneCost + algoNotDoneCost );
1817       }
1818       else
1819       {
1820         rate = algo->GetProgressByTic();
1821         computedCost += algoDoneCost + rate * algoNotDoneCost;
1822       }
1823       // cout << "rate: "<<rate << " algoNotDoneCost: " << algoNotDoneCost << endl;
1824     }
1825
1826   // get cost of already treated sub-meshes
1827   if ( SMESH_subMesh* mainSM = GetSubMeshContaining( 1 ))
1828   {
1829     SMESH_subMeshIteratorPtr smIt = mainSM->getDependsOnIterator(/*includeSelf=*/true);
1830     while ( smIt->more() )
1831     {
1832       const SMESH_subMesh* sm = smIt->next();
1833       const int smCost = sm->GetComputeCost();
1834       totalCost += smCost;
1835       if ( !currentSubIds.Contains( sm->GetId() ) )
1836       {
1837         if (( !sm->IsEmpty() ) ||
1838             ( sm->GetComputeState() == SMESH_subMesh::FAILED_TO_COMPUTE &&
1839               !sm->DependsOn( curSM ) ))
1840           computedCost += smCost;
1841       }
1842     }
1843   }
1844   // cout << "Total: " << totalCost
1845   //      << " computed: " << computedCost << " progress: " << computedCost / totalCost
1846   //      << " nbElems: " << GetMeshDS()->GetMeshInfo().NbElements() << endl;
1847   return computedCost / totalCost;
1848 }
1849
1850 //================================================================================
1851 /*!
1852  * \brief Return number of nodes in the mesh
1853  */
1854 //================================================================================
1855
1856 smIdType SMESH_Mesh::NbNodes() const
1857 {
1858   return _meshDS->NbNodes();
1859 }
1860
1861 //================================================================================
1862 /*!
1863  * \brief  Return number of edges of given order in the mesh
1864  */
1865 //================================================================================
1866
1867 smIdType SMESH_Mesh::Nb0DElements() const
1868 {
1869   return _meshDS->GetMeshInfo().Nb0DElements();
1870 }
1871
1872 //================================================================================
1873 /*!
1874  * \brief  Return number of edges of given order in the mesh
1875  */
1876 //================================================================================
1877
1878 smIdType SMESH_Mesh::NbEdges(SMDSAbs_ElementOrder order) const
1879 {
1880   return _meshDS->GetMeshInfo().NbEdges(order);
1881 }
1882
1883 //================================================================================
1884 /*!
1885  * \brief Return number of faces of given order in the mesh
1886  */
1887 //================================================================================
1888
1889 smIdType SMESH_Mesh::NbFaces(SMDSAbs_ElementOrder order) const
1890 {
1891   return _meshDS->GetMeshInfo().NbFaces(order);
1892 }
1893
1894 //================================================================================
1895 /*!
1896  * \brief Return the number of faces in the mesh
1897  */
1898 //================================================================================
1899
1900 smIdType SMESH_Mesh::NbTriangles(SMDSAbs_ElementOrder order) const
1901 {
1902   return _meshDS->GetMeshInfo().NbTriangles(order);
1903 }
1904
1905 //================================================================================
1906 /*!
1907  * \brief Return number of biquadratic triangles in the mesh
1908  */
1909 //================================================================================
1910
1911 smIdType SMESH_Mesh::NbBiQuadTriangles() const
1912 {
1913   return _meshDS->GetMeshInfo().NbBiQuadTriangles();
1914 }
1915
1916 //================================================================================
1917 /*!
1918  * \brief Return the number nodes faces in the mesh
1919  */
1920 //================================================================================
1921
1922 smIdType SMESH_Mesh::NbQuadrangles(SMDSAbs_ElementOrder order) const
1923 {
1924   return _meshDS->GetMeshInfo().NbQuadrangles(order);
1925 }
1926
1927 //================================================================================
1928 /*!
1929  * \brief Return number of biquadratic quadrangles in the mesh
1930  */
1931 //================================================================================
1932
1933 smIdType SMESH_Mesh::NbBiQuadQuadrangles() const
1934 {
1935   return _meshDS->GetMeshInfo().NbBiQuadQuadrangles();
1936 }
1937
1938 //================================================================================
1939 /*!
1940  * \brief Return the number of polygonal faces in the mesh
1941  */
1942 //================================================================================
1943
1944 smIdType SMESH_Mesh::NbPolygons(SMDSAbs_ElementOrder order) const
1945 {
1946   return _meshDS->GetMeshInfo().NbPolygons(order);
1947 }
1948
1949 //================================================================================
1950 /*!
1951  * \brief Return number of volumes of given order in the mesh
1952  */
1953 //================================================================================
1954
1955 smIdType SMESH_Mesh::NbVolumes(SMDSAbs_ElementOrder order) const
1956 {
1957   return _meshDS->GetMeshInfo().NbVolumes(order);
1958 }
1959
1960 //================================================================================
1961 /*!
1962  * \brief  Return number of tetrahedrons of given order in the mesh
1963  */
1964 //================================================================================
1965
1966 smIdType SMESH_Mesh::NbTetras(SMDSAbs_ElementOrder order) const
1967 {
1968   return _meshDS->GetMeshInfo().NbTetras(order);
1969 }
1970
1971 //================================================================================
1972 /*!
1973  * \brief  Return number of hexahedrons of given order in the mesh
1974  */
1975 //================================================================================
1976
1977 smIdType SMESH_Mesh::NbHexas(SMDSAbs_ElementOrder order) const
1978 {
1979   return _meshDS->GetMeshInfo().NbHexas(order);
1980 }
1981
1982 //================================================================================
1983 /*!
1984  * \brief  Return number of triquadratic hexahedrons in the mesh
1985  */
1986 //================================================================================
1987
1988 smIdType SMESH_Mesh::NbTriQuadraticHexas() const
1989 {
1990   return _meshDS->GetMeshInfo().NbTriQuadHexas();
1991 }
1992
1993 //================================================================================
1994 /*!
1995  * \brief  Return number of pyramids of given order in the mesh
1996  */
1997 //================================================================================
1998
1999 smIdType SMESH_Mesh::NbPyramids(SMDSAbs_ElementOrder order) const
2000 {
2001   return _meshDS->GetMeshInfo().NbPyramids(order);
2002 }
2003
2004 //================================================================================
2005 /*!
2006  * \brief  Return number of prisms (penthahedrons) of given order in the mesh
2007  */
2008 //================================================================================
2009
2010 smIdType SMESH_Mesh::NbPrisms(SMDSAbs_ElementOrder order) const
2011 {
2012   return _meshDS->GetMeshInfo().NbPrisms(order);
2013 }
2014
2015 smIdType SMESH_Mesh::NbQuadPrisms() const
2016 {
2017   return _meshDS->GetMeshInfo().NbQuadPrisms();
2018 }
2019
2020 smIdType SMESH_Mesh::NbBiQuadPrisms() const
2021 {
2022   return _meshDS->GetMeshInfo().NbBiQuadPrisms();
2023 }
2024
2025
2026 //================================================================================
2027 /*!
2028  * \brief  Return number of hexagonal prisms in the mesh
2029  */
2030 //================================================================================
2031
2032 smIdType SMESH_Mesh::NbHexagonalPrisms() const
2033 {
2034   return _meshDS->GetMeshInfo().NbHexPrisms();
2035 }
2036
2037 //================================================================================
2038 /*!
2039  * \brief  Return number of polyhedrons in the mesh
2040  */
2041 //================================================================================
2042
2043 smIdType SMESH_Mesh::NbPolyhedrons() const
2044 {
2045   return _meshDS->GetMeshInfo().NbPolyhedrons();
2046 }
2047
2048 //================================================================================
2049 /*!
2050  * \brief  Return number of ball elements in the mesh
2051  */
2052 //================================================================================
2053
2054 smIdType SMESH_Mesh::NbBalls() const
2055 {
2056   return _meshDS->GetMeshInfo().NbBalls();
2057 }
2058
2059 //================================================================================
2060 /*!
2061  * \brief  Return number of submeshes in the mesh
2062  */
2063 //================================================================================
2064
2065 smIdType SMESH_Mesh::NbSubMesh() const
2066 {
2067   return _meshDS->NbSubMesh();
2068 }
2069
2070 //================================================================================
2071 /*!
2072  * \brief Returns number of meshes in the Study, that is supposed to be
2073  *        equal to SMESHDS_Document::NbMeshes()
2074  */
2075 //================================================================================
2076
2077 int SMESH_Mesh::NbMeshes() const // nb meshes in the Study
2078 {
2079   return _document->NbMeshes();
2080 }
2081
2082 //=======================================================================
2083 //function : IsNotConformAllowed
2084 //purpose  : check if a hypothesis allowing notconform mesh is present
2085 //=======================================================================
2086
2087 bool SMESH_Mesh::IsNotConformAllowed() const
2088 {
2089   if(MYDEBUG) MESSAGE("SMESH_Mesh::IsNotConformAllowed");
2090
2091   static SMESH_HypoFilter filter( SMESH_HypoFilter::HasName( "NotConformAllowed" ));
2092   return GetHypothesis( _meshDS->ShapeToMesh(), filter, false );
2093 }
2094
2095 //=======================================================================
2096 //function : IsMainShape
2097 //purpose  : 
2098 //=======================================================================
2099
2100 bool SMESH_Mesh::IsMainShape(const TopoDS_Shape& theShape) const
2101 {
2102   return theShape.IsSame(_meshDS->ShapeToMesh() );
2103 }
2104
2105 //=======================================================================
2106 //function : GetShapeByEntry
2107 //purpose  : return TopoDS_Shape by its study entry
2108 //=======================================================================
2109
2110 TopoDS_Shape SMESH_Mesh::GetShapeByEntry(const std::string& entry) const
2111 {
2112   return _callUp ? _callUp->GetShapeByEntry( entry ) : TopoDS_Shape();
2113 }
2114
2115 //=============================================================================
2116 /*!
2117  *  
2118  */
2119 //=============================================================================
2120
2121 SMESH_Group* SMESH_Mesh::AddGroup (const SMDSAbs_ElementType theType,
2122                                    const char*               theName,
2123                                    const int                 theId,
2124                                    const TopoDS_Shape&       theShape,
2125                                    const SMESH_PredicatePtr& thePredicate)
2126 {
2127   if ( _mapGroup.count( theId ))
2128     return NULL;
2129   int id = ( theId < 0 ) ? _groupId : theId;
2130   SMESH_Group* aGroup = new SMESH_Group ( id, this, theType, theName, theShape, thePredicate );
2131   GetMeshDS()->AddGroup( aGroup->GetGroupDS() );
2132   _mapGroup[ id ] = aGroup;
2133   _groupId = 1 + _mapGroup.rbegin()->first;
2134   return aGroup;
2135 }
2136
2137 //================================================================================
2138 /*!
2139  * \brief Creates a group based on an existing SMESHDS group. Group ID should be unique
2140  */
2141 //================================================================================
2142
2143 SMESH_Group* SMESH_Mesh::AddGroup (SMESHDS_GroupBase* groupDS)
2144 {
2145   if ( !groupDS )
2146     throw SALOME_Exception(LOCALIZED ("SMESH_Mesh::AddGroup(): NULL SMESHDS_GroupBase"));
2147
2148   std::map <int, SMESH_Group*>::iterator i_g = _mapGroup.find( groupDS->GetID() );
2149   if ( i_g != _mapGroup.end() && i_g->second )
2150   {
2151     if ( i_g->second->GetGroupDS() == groupDS )
2152       return i_g->second;
2153     else
2154       throw SALOME_Exception(LOCALIZED ("SMESH_Mesh::AddGroup() wrong ID of SMESHDS_GroupBase"));
2155   }
2156   SMESH_Group* aGroup = new SMESH_Group (groupDS);
2157   _mapGroup[ groupDS->GetID() ] = aGroup;
2158   GetMeshDS()->AddGroup( aGroup->GetGroupDS() );
2159
2160   _groupId = 1 + _mapGroup.rbegin()->first;
2161
2162   return aGroup;
2163 }
2164
2165
2166 //================================================================================
2167 /*!
2168  * \brief Creates SMESH_Groups for not wrapped SMESHDS_Groups
2169  *  \retval bool - true if new SMESH_Groups have been created
2170  *
2171  */
2172 //================================================================================
2173
2174 bool SMESH_Mesh::SynchronizeGroups()
2175 {
2176   const size_t                            nbGroups = _mapGroup.size();
2177   const std::set<SMESHDS_GroupBase*>&       groups = _meshDS->GetGroups();
2178   std::set<SMESHDS_GroupBase*>::const_iterator gIt = groups.begin();
2179   for ( ; gIt != groups.end(); ++gIt )
2180   {
2181     SMESHDS_GroupBase* groupDS = (SMESHDS_GroupBase*) *gIt;
2182     _groupId = groupDS->GetID();
2183     if ( !_mapGroup.count( _groupId ))
2184       _mapGroup[_groupId] = new SMESH_Group( groupDS );
2185   }
2186   if ( !_mapGroup.empty() )
2187     _groupId = 1 + _mapGroup.rbegin()->first;
2188
2189   return nbGroups < _mapGroup.size();
2190 }
2191
2192 //================================================================================
2193 /*!
2194  * \brief Return iterator on all existing groups
2195  */
2196 //================================================================================
2197
2198 SMESH_Mesh::GroupIteratorPtr SMESH_Mesh::GetGroups() const
2199 {
2200   typedef std::map <int, SMESH_Group *> TMap;
2201   return GroupIteratorPtr( new SMDS_mapIterator<TMap>( _mapGroup ));
2202 }
2203
2204 //=============================================================================
2205 /*!
2206  * \brief Return a group by ID
2207  */
2208 //=============================================================================
2209
2210 SMESH_Group* SMESH_Mesh::GetGroup (const int theGroupID) const
2211 {
2212   std::map <int, SMESH_Group*>::const_iterator id_grp = _mapGroup.find( theGroupID );
2213   if ( id_grp == _mapGroup.end() )
2214     return NULL;
2215   return id_grp->second;
2216 }
2217
2218
2219 //=============================================================================
2220 /*!
2221  * \brief Return IDs of all groups
2222  */
2223 //=============================================================================
2224
2225 std::list<int> SMESH_Mesh::GetGroupIds() const
2226 {
2227   std::list<int> anIds;
2228   std::map<int, SMESH_Group*>::const_iterator it = _mapGroup.begin();
2229   for ( ; it != _mapGroup.end(); it++ )
2230     anIds.push_back( it->first );
2231   
2232   return anIds;
2233 }
2234
2235 //================================================================================
2236 /*!
2237  * \brief Set a caller of methods at level of CORBA API implementation.
2238  * The set upCaller will be deleted by SMESH_Mesh
2239  */
2240 //================================================================================
2241
2242 void SMESH_Mesh::SetCallUp( TCallUp* upCaller )
2243 {
2244   if ( _callUp ) delete _callUp;
2245   _callUp = upCaller;
2246 }
2247
2248 //=============================================================================
2249 /*!
2250  *  
2251  */
2252 //=============================================================================
2253
2254 bool SMESH_Mesh::RemoveGroup( const int theGroupID )
2255 {
2256   if (_mapGroup.find(theGroupID) == _mapGroup.end())
2257     return false;
2258   GetMeshDS()->RemoveGroup( _mapGroup[theGroupID]->GetGroupDS() );
2259   delete _mapGroup[theGroupID];
2260   _mapGroup.erase (theGroupID);
2261   if (_callUp)
2262     _callUp->RemoveGroup( theGroupID );
2263   return true;
2264 }
2265
2266 //=======================================================================
2267 //function : GetAncestors
2268 //purpose  : return list of ancestors of theSubShape in the order
2269 //           that lower dimension shapes come first.
2270 //=======================================================================
2271
2272 const TopTools_ListOfShape& SMESH_Mesh::GetAncestors(const TopoDS_Shape& theS) const
2273 {
2274   if ( _mapAncestors.Contains( theS ) )
2275     return _mapAncestors.FindFromKey( theS );
2276
2277   static TopTools_ListOfShape emptyList;
2278   return emptyList;
2279 }
2280
2281 //=======================================================================
2282 //function : Dump
2283 //purpose  : dumps contents of mesh to stream [ debug purposes ]
2284 //=======================================================================
2285
2286 ostream& SMESH_Mesh::Dump(ostream& save)
2287 {
2288   int clause = 0;
2289   save << "========================== Dump contents of mesh ==========================" << endl << endl;
2290   save << ++clause << ") Total number of nodes:      \t" << NbNodes() << endl;
2291   save << ++clause << ") Total number of edges:      \t" << NbEdges() << endl;
2292   save << ++clause << ") Total number of faces:      \t" << NbFaces() << endl;
2293   save << ++clause << ") Total number of polygons:   \t" << NbPolygons() << endl;
2294   save << ++clause << ") Total number of volumes:    \t" << NbVolumes() << endl;
2295   save << ++clause << ") Total number of polyhedrons:\t" << NbPolyhedrons() << endl << endl;
2296   for ( int isQuadratic = 0; isQuadratic < 2; ++isQuadratic )
2297   {
2298     std::string orderStr = isQuadratic ? "quadratic" : "linear";
2299     SMDSAbs_ElementOrder order  = isQuadratic ? ORDER_QUADRATIC : ORDER_LINEAR;
2300
2301     save << ++clause << ") Total number of " << orderStr << " edges:\t" << NbEdges(order) << endl;
2302     save << ++clause << ") Total number of " << orderStr << " faces:\t" << NbFaces(order) << endl;
2303     if ( NbFaces(order) > 0 ) {
2304       smIdType nb3 = NbTriangles(order);
2305       smIdType nb4 = NbQuadrangles(order);
2306       save << clause << ".1) Number of " << orderStr << " triangles:  \t" << nb3 << endl;
2307       save << clause << ".2) Number of " << orderStr << " quadrangles:\t" << nb4 << endl;
2308       if ( nb3 + nb4 !=  NbFaces(order) ) {
2309         std::map<int,int> myFaceMap;
2310         SMDS_FaceIteratorPtr itFaces=_meshDS->facesIterator();
2311         while( itFaces->more( ) ) {
2312           int nbNodes = itFaces->next()->NbNodes();
2313           if ( myFaceMap.find( nbNodes ) == myFaceMap.end() )
2314             myFaceMap[ nbNodes ] = 0;
2315           myFaceMap[ nbNodes ] = myFaceMap[ nbNodes ] + 1;
2316         }
2317         save << clause << ".3) Faces in detail: " << endl;
2318         std::map <int,int>::iterator itF;
2319         for (itF = myFaceMap.begin(); itF != myFaceMap.end(); itF++)
2320           save << "--> nb nodes: " << itF->first << " - nb elements:\t" << itF->second << endl;
2321       }
2322     }
2323     save << ++clause << ") Total number of " << orderStr << " volumes:\t" << NbVolumes(order) << endl;
2324     if ( NbVolumes(order) > 0 ) {
2325       smIdType nb8 = NbHexas(order);
2326       smIdType nb4 = NbTetras(order);
2327       smIdType nb5 = NbPyramids(order);
2328       smIdType nb6 = NbPrisms(order);
2329       save << clause << ".1) Number of " << orderStr << " hexahedrons: \t" << nb8 << endl;
2330       save << clause << ".2) Number of " << orderStr << " tetrahedrons:\t" << nb4 << endl;
2331       save << clause << ".3) Number of " << orderStr << " prisms:      \t" << nb6 << endl;
2332       save << clause << ".4) Number of " << orderStr << " pyramids:    \t" << nb5 << endl;
2333       if ( nb8 + nb4 + nb5 + nb6 != NbVolumes(order) ) {
2334         std::map<int,int> myVolumesMap;
2335         SMDS_VolumeIteratorPtr itVolumes=_meshDS->volumesIterator();
2336         while( itVolumes->more( ) ) {
2337           int nbNodes = itVolumes->next()->NbNodes();
2338           if ( myVolumesMap.find( nbNodes ) == myVolumesMap.end() )
2339             myVolumesMap[ nbNodes ] = 0;
2340           myVolumesMap[ nbNodes ] = myVolumesMap[ nbNodes ] + 1;
2341         }
2342         save << clause << ".5) Volumes in detail: " << endl;
2343         std::map <int,int>::iterator itV;
2344         for (itV = myVolumesMap.begin(); itV != myVolumesMap.end(); itV++)
2345           save << "--> nb nodes: " << itV->first << " - nb elements:\t" << itV->second << endl;
2346       }
2347     }
2348     save << endl;
2349   }
2350   save << "===========================================================================" << endl;
2351   return save;
2352 }
2353
2354 //=======================================================================
2355 //function : GetElementType
2356 //purpose  : Returns type of mesh element with certain id
2357 //=======================================================================
2358
2359 SMDSAbs_ElementType SMESH_Mesh::GetElementType( const smIdType id, const bool iselem )
2360 {
2361   return _meshDS->GetElementType( id, iselem );
2362 }
2363
2364 //=============================================================================
2365 /*!
2366  *  \brief Convert group on geometry into standalone group
2367  */
2368 //=============================================================================
2369
2370 SMESH_Group* SMESH_Mesh::ConvertToStandalone ( int theGroupID )
2371 {
2372   SMESH_Group* aGroup = 0;
2373   std::map < int, SMESH_Group * >::iterator itg = _mapGroup.find( theGroupID );
2374   if ( itg == _mapGroup.end() )
2375     return aGroup;
2376
2377   SMESH_Group* anOldGrp = (*itg).second;
2378   if ( !anOldGrp || !anOldGrp->GetGroupDS() )
2379     return aGroup;
2380   SMESHDS_GroupBase* anOldGrpDS = anOldGrp->GetGroupDS();
2381
2382   // create new standalone group
2383   aGroup = new SMESH_Group (theGroupID, this, anOldGrpDS->GetType(), anOldGrp->GetName() );
2384   _mapGroup[theGroupID] = aGroup;
2385
2386   SMESHDS_Group* aNewGrpDS = dynamic_cast<SMESHDS_Group*>( aGroup->GetGroupDS() );
2387   GetMeshDS()->RemoveGroup( anOldGrpDS );
2388   GetMeshDS()->AddGroup( aNewGrpDS );
2389
2390   // add elements (or nodes) into new created group
2391   SMDS_ElemIteratorPtr anItr = anOldGrpDS->GetElements();
2392   while ( anItr->more() )
2393     aNewGrpDS->Add( (anItr->next())->GetID() );
2394
2395   // set color
2396   aNewGrpDS->SetColor( anOldGrpDS->GetColor() );
2397
2398   // remove old group
2399   delete anOldGrp;
2400
2401   return aGroup;
2402 }
2403
2404 //=============================================================================
2405 /*!
2406  *  \brief remove submesh order  from Mesh
2407  */
2408 //=============================================================================
2409
2410 void SMESH_Mesh::ClearMeshOrder()
2411 {
2412   _subMeshOrder.clear();
2413 }
2414
2415 //=============================================================================
2416 /*!
2417  *  \brief remove submesh order  from Mesh
2418  */
2419 //=============================================================================
2420
2421 void SMESH_Mesh::SetMeshOrder(const TListOfListOfInt& theOrder )
2422 {
2423   _subMeshOrder = theOrder;
2424 }
2425
2426 //=============================================================================
2427 /*!
2428  *  \brief return submesh order if any
2429  */
2430 //=============================================================================
2431
2432 const TListOfListOfInt& SMESH_Mesh::GetMeshOrder() const
2433 {
2434   return _subMeshOrder;
2435 }
2436
2437 //=============================================================================
2438 /*!
2439  *  \brief fill _mapAncestors
2440  */
2441 //=============================================================================
2442
2443 void SMESH_Mesh::fillAncestorsMap(const TopoDS_Shape& theShape)
2444 {
2445   int desType, ancType;
2446   if ( !theShape.IsSame( GetShapeToMesh()) && theShape.ShapeType() == TopAbs_COMPOUND )
2447   {
2448     // a geom group is added. Insert it into lists of ancestors before
2449     // the first ancestor more complex than group members
2450     TopoDS_Iterator subIt( theShape );
2451     if ( !subIt.More() ) return;
2452     int memberType = subIt.Value().ShapeType();
2453     for ( desType = TopAbs_VERTEX; desType >= memberType; desType-- )
2454       for (TopExp_Explorer des( theShape, TopAbs_ShapeEnum( desType )); des.More(); des.Next())
2455       {
2456         if ( !_mapAncestors.Contains( des.Current() )) continue;// issue 0020982
2457         TopTools_ListOfShape& ancList = _mapAncestors.ChangeFromKey( des.Current() );
2458         TopTools_ListIteratorOfListOfShape ancIt (ancList);
2459         while ( ancIt.More() && ancIt.Value().ShapeType() >= memberType )
2460           ancIt.Next();
2461         if ( ancIt.More() ) ancList.InsertBefore( theShape, ancIt );
2462         else                ancList.Append( theShape );
2463       }
2464   }
2465   else // else added for 52457: Addition of hypotheses is 8 time longer than meshing
2466   {
2467     for ( desType = TopAbs_VERTEX; desType > TopAbs_COMPOUND; desType-- )
2468       for ( ancType = desType - 1; ancType >= TopAbs_COMPOUND; ancType-- )
2469         TopExp::MapShapesAndAncestors ( theShape,
2470                                         (TopAbs_ShapeEnum) desType,
2471                                         (TopAbs_ShapeEnum) ancType,
2472                                         _mapAncestors );
2473   }
2474   // visit COMPOUNDs inside a COMPOUND that are not reachable by TopExp_Explorer
2475   if ( theShape.ShapeType() == TopAbs_COMPOUND )
2476   {
2477     TopoDS_Iterator sIt(theShape);
2478     if ( sIt.More() && sIt.Value().ShapeType() == TopAbs_COMPOUND )
2479       for ( ; sIt.More(); sIt.Next() )
2480         if ( sIt.Value().ShapeType() == TopAbs_COMPOUND )
2481           fillAncestorsMap( sIt.Value() );
2482   }
2483 }
2484
2485 //=============================================================================
2486 /*!
2487  * \brief sort submeshes according to stored mesh order
2488  * \param theListToSort in out list to be sorted
2489  * \return FALSE if nothing sorted
2490  */
2491 //=============================================================================
2492
2493 bool SMESH_Mesh::SortByMeshOrder(std::vector<SMESH_subMesh*>& theListToSort) const
2494 {
2495   if ( _subMeshOrder.empty() || theListToSort.size() < 2 )
2496     return true;
2497
2498
2499   // collect all ordered sub-meshes in smVec as pointers
2500   // and get their positions within theListToSort
2501
2502   std::vector<SMESH_subMesh*> smVec;
2503   typedef std::vector<SMESH_subMesh*>::iterator TPosInList;
2504   std::map< size_t, size_t > sortedPos; // index in theListToSort to order
2505   TPosInList smBeg = theListToSort.begin(), smEnd = theListToSort.end();
2506   TListOfListOfInt::const_iterator      listIdsIt = _subMeshOrder.begin();
2507   bool needSort = false;
2508   for( ; listIdsIt != _subMeshOrder.end(); listIdsIt++)
2509   {
2510     const TListOfInt& listOfId = *listIdsIt;
2511     // convert sm ids to sm's
2512     smVec.clear();
2513     TListOfInt::const_iterator idIt = listOfId.begin();
2514     for ( ; idIt != listOfId.end(); idIt++ )
2515     {
2516       if ( SMESH_subMesh * sm = GetSubMeshContaining( *idIt ))
2517       {
2518         smVec.push_back( sm );
2519         if ( sm->GetSubMeshDS() && sm->GetSubMeshDS()->IsComplexSubmesh() )
2520         {
2521           smVec.reserve( smVec.size() + sm->GetSubMeshDS()->NbSubMeshes() );
2522           SMESHDS_SubMeshIteratorPtr smdsIt = sm->GetSubMeshDS()->GetSubMeshIterator();
2523           while ( smdsIt->more() )
2524           {
2525             const SMESHDS_SubMesh* smDS = smdsIt->next();
2526             if (( sm = GetSubMeshContaining( smDS->GetID() )))
2527               smVec.push_back( sm );
2528           }
2529         }
2530       }
2531     }
2532     // find smVec items in theListToSort
2533     for ( size_t i = 0; i < smVec.size(); ++i )
2534     {
2535       TPosInList smPos = find( smBeg, smEnd, smVec[i] ); // position in theListToSort
2536       if ( smPos != smEnd )
2537       {
2538         size_t posInList = std::distance( smBeg, smPos );
2539         size_t     order = sortedPos.size();
2540         sortedPos.insert( std::make_pair( posInList, order ));
2541         if ( posInList != order )
2542           needSort = true;
2543       }
2544     }
2545   }
2546   if ( ! needSort )
2547     return false;
2548
2549   // set sm of sortedPos from theListToSort to front of orderedSM
2550   // and the rest of theListToSort to orderedSM end
2551
2552   std::vector<SMESH_subMesh*> orderedSM;
2553   orderedSM.reserve( theListToSort.size() );
2554   orderedSM.resize( sortedPos.size() );
2555
2556   size_t iPrev = 0;
2557   sortedPos.insert( std::make_pair( theListToSort.size(), sortedPos.size() ));
2558   for ( const auto & pos_order : sortedPos )
2559   {
2560     const size_t& posInList = pos_order.first;
2561     const size_t&     order = pos_order.second;
2562     if ( order < sortedPos.size() - 1 )
2563       orderedSM[ order ] = theListToSort[ posInList ];
2564
2565     if ( iPrev < posInList )
2566       orderedSM.insert( orderedSM.end(),
2567                         theListToSort.begin() + iPrev,
2568                         theListToSort.begin() + posInList );
2569     iPrev = posInList + 1;
2570   }
2571
2572   theListToSort.swap( orderedSM );
2573
2574   return true;
2575 }
2576
2577 //================================================================================
2578 /*!
2579  * \brief Return true if given order of sub-meshes is OK
2580  */
2581 //================================================================================
2582
2583 bool SMESH_Mesh::IsOrderOK( const SMESH_subMesh* smBefore,
2584                             const SMESH_subMesh* smAfter ) const
2585 {
2586   TListOfListOfInt::const_iterator listIdsIt = _subMeshOrder.begin();
2587   for( ; listIdsIt != _subMeshOrder.end(); listIdsIt++)
2588   {
2589     const TListOfInt& listOfId = *listIdsIt;
2590     int iB = -1, iA = -1, i = 0;
2591     for ( TListOfInt::const_iterator id = listOfId.begin(); id != listOfId.end(); ++id, ++i )
2592     {
2593       if ( *id == smBefore->GetId() )
2594       {
2595         iB = i;
2596         if ( iA > -1 )
2597           return iB < iA;
2598       }
2599       else if ( *id == smAfter->GetId() )
2600       {
2601         iA = i;
2602         if ( iB > -1 )
2603           return iB < iA;
2604       }
2605     }
2606   }
2607   return true; // no order imposed to given sub-meshes
2608
2609
2610 //=============================================================================
2611 /*!
2612  * \brief sort submeshes according to stored mesh order
2613  * \param theListToSort in out list to be sorted
2614  * \return FALSE if nothing sorted
2615  */
2616 //=============================================================================
2617
2618 void SMESH_Mesh::getAncestorsSubMeshes (const TopoDS_Shape&            theSubShape,
2619                                         std::vector< SMESH_subMesh* >& theSubMeshes) const
2620 {
2621   theSubMeshes.clear();
2622   TopTools_ListIteratorOfListOfShape it( GetAncestors( theSubShape ));
2623   for (; it.More(); it.Next() )
2624     if ( SMESH_subMesh* sm = GetSubMeshContaining( it.Value() ))
2625       theSubMeshes.push_back(sm);
2626
2627   // sort submeshes according to stored mesh order
2628   SortByMeshOrder( theSubMeshes );
2629 }