Salome HOME
Merge branch 'V9_9_BR'
[modules/smesh.git] / src / SMESH_I / SMESH_Mesh_i.cxx
1 // Copyright (C) 2007-2022  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : SMESH_Mesh_i.cxx
23 //  Author : Paul RASCLE, EDF
24 //  Module : SMESH
25
26 #include "SMESH_Mesh_i.hxx"
27
28 #include "DriverMED_R_SMESHDS_Mesh.h"
29 #include "DriverMED_W_Field.h"
30 #include "DriverMED_W_SMESHDS_Mesh.h"
31 #include "MED_Factory.hxx"
32 #include "SMDS_LinearEdge.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_ElemIterator.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_IteratorOnIterators.hxx"
37 #include "SMDS_MeshGroup.hxx"
38 #include "SMDS_SetIterator.hxx"
39 #include "SMDS_StdIterator.hxx"
40 #include "SMDS_VolumeTool.hxx"
41 #include "SMESHDS_Command.hxx"
42 #include "SMESHDS_CommandType.hxx"
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_GroupOnGeom.hxx"
45 #include "SMESH_Controls.hxx"
46 #include "SMESH_File.hxx"
47 #include "SMESH_Filter_i.hxx"
48 #include "SMESH_Gen_i.hxx"
49 #include "SMESH_Group.hxx"
50 #include "SMESH_Group_i.hxx"
51 #include "SMESH_Mesh.hxx"
52 #include "SMESH_MeshAlgos.hxx"
53 #include "SMESH_MeshEditor.hxx"
54 #include "SMESH_MeshEditor_i.hxx"
55 #include "SMESH_MeshPartDS.hxx"
56 #include "SMESH_MesherHelper.hxx"
57 #include "SMESH_PreMeshInfo.hxx"
58 #include "SMESH_PythonDump.hxx"
59 #include "SMESH_subMesh_i.hxx"
60
61 #include <SALOMEDS_Attributes_wrap.hxx>
62 #include <SALOMEDS_wrap.hxx>
63 #include <Utils_ExceptHandlers.hxx>
64 #include <utilities.h>
65
66 #include <GEOMImpl_Types.hxx>
67 #include <GEOM_wrap.hxx>
68
69 // OCCT Includes
70 #include <BRep_Builder.hxx>
71 #include <Standard_ErrorHandler.hxx>
72 #include <TColStd_MapOfInteger.hxx>
73 #include <TopExp.hxx>
74 #include <TopExp_Explorer.hxx>
75 #include <TopTools_DataMapOfShapeShape.hxx>
76 #include <TopTools_MapIteratorOfMapOfShape.hxx>
77 #include <TopTools_MapOfShape.hxx>
78 #include <TopoDS_Compound.hxx>
79
80 // STL Includes
81 #include <algorithm>
82 #include <iostream>
83 #include <sstream>
84
85 #include <vtkUnstructuredGridWriter.h>
86
87 // to pass CORBA exception and TooLargeForExport exception through SMESH_TRY
88 #define SMY_OWN_CATCH                                                                           \
89   catch( SALOME::SALOME_Exception& se ) { throw se; }                                           \
90   catch( ::SMESH_Mesh::TooLargeForExport& ex )                                                  \
91   { SALOME::ExceptionStruct se = {                                                              \
92       SALOME::COMM,                                                                             \
93       CORBA::string_dup(SMESH_Comment("Mesh is too large for export in format ") << ex.what()), \
94       CORBA::string_dup(SMESH_Comment("format=") <<  ex.what() ), 0 };                          \
95     throw SALOME::SALOME_Exception( se );  }
96
97 #include "SMESH_TryCatch.hxx" // include after OCCT headers!
98
99 #ifdef _DEBUG_
100 static int MYDEBUG = 0;
101 #else
102 static int MYDEBUG = 0;
103 #endif
104
105 using namespace std;
106 using SMESH::TPythonDump;
107 using SMESH::TVar;
108
109 int SMESH_Mesh_i::_idGenerator = 0;
110
111 //=============================================================================
112 /*!
113  *  Constructor
114  */
115 //=============================================================================
116
117 SMESH_Mesh_i::SMESH_Mesh_i( PortableServer::POA_ptr thePOA,
118                             SMESH_Gen_i*            gen_i )
119 : SALOME::GenericObj_i( thePOA )
120 {
121   _impl          = NULL;
122   _gen_i         = gen_i;
123   _id            = _idGenerator++;
124   _nbInvalidHypos= -1;
125   _editor        = NULL;
126   _previewEditor = NULL;
127   _preMeshInfo   = NULL;
128   _mainShapeTick = 0;
129 }
130
131 //=============================================================================
132 /*!
133  *  Destructor
134  */
135 //=============================================================================
136
137 SMESH_Mesh_i::~SMESH_Mesh_i()
138 {
139   // destroy groups
140   map<int, SMESH::SMESH_GroupBase_ptr>::iterator itGr;
141   for (itGr = _mapGroups.begin(); itGr != _mapGroups.end(); itGr++)
142     if (SMESH_GroupBase_i* aGroup = SMESH::DownCast<SMESH_GroupBase_i*>(itGr->second))
143     {
144       aGroup->UnRegister();
145       SMESH::SMESH_GroupBase_var( itGr->second );
146     }
147   _mapGroups.clear();
148
149   // destroy submeshes
150   map<int, SMESH::SMESH_subMesh_ptr>::iterator itSM;
151   for ( itSM = _mapSubMeshIor.begin(); itSM != _mapSubMeshIor.end(); itSM++ )
152     if ( SMESH_subMesh_i* aSubMesh = SMESH::DownCast<SMESH_subMesh_i*>( itSM->second ))
153     {
154       aSubMesh->UnRegister();
155       SMESH::SMESH_subMesh_var( itSM->second );
156     }
157   _mapSubMeshIor.clear();
158
159   // destroy hypotheses. _mapHypo contains all hyps ever been assigned
160   map<int, SMESH::SMESH_Hypothesis_ptr>::iterator itH;
161   for ( itH = _mapHypo.begin(); itH != _mapHypo.end(); itH++ ) {
162     if ( SMESH_Hypothesis_i* hyp_i = SMESH::DownCast<SMESH_Hypothesis_i*>( itH->second ))
163       if ( SMESH_Hypothesis * smHyp = _impl->GetHypothesis( itH->first ))
164         if ( _impl->GetMeshDS()->IsUsedHypothesis( smHyp ))
165           hyp_i->UnRegister();
166
167     SMESH::SMESH_Hypothesis_var( itH->second ); // decref CORBA object
168   }
169   _mapHypo.clear();
170
171   // clear cached shapes if no more meshes remain; (the cache is blame,
172   // together with publishing, of spent time increasing in issue 22874)
173   if ( _impl->NbMeshes() == 1 )
174     _gen_i->GetShapeReader()->ClearClientBuffer();
175
176   delete _editor; _editor = NULL;
177   delete _previewEditor; _previewEditor = NULL;
178   delete _impl; _impl = NULL;
179   delete _preMeshInfo; _preMeshInfo = NULL;
180 }
181
182 //=============================================================================
183 /*!
184  *  SetShape
185  *
186  *  Associate <this> mesh with <theShape> and put a reference
187  *  to <theShape> into the current study;
188  *  the previous shape is substituted by the new one.
189  */
190 //=============================================================================
191
192 void SMESH_Mesh_i::SetShape( GEOM::GEOM_Object_ptr theShapeObject )
193 {
194   Unexpect aCatch(SALOME_SalomeException);
195   try {
196     _impl->ShapeToMesh( _gen_i->GeomObjectToShape( theShapeObject ));
197   }
198   catch(SALOME_Exception & S_ex) {
199     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
200   }
201   // to track changes of GEOM groups
202   SMESH::SMESH_Mesh_var mesh = _this();
203   addGeomGroupData( theShapeObject, mesh );
204   if ( !CORBA::is_nil( theShapeObject ))
205     _mainShapeTick = theShapeObject->GetTick();
206 }
207
208 //================================================================================
209 /*!
210  * \brief Return true if mesh has a shape to build a shape on
211  */
212 //================================================================================
213
214 CORBA::Boolean SMESH_Mesh_i::HasShapeToMesh()
215 {
216   Unexpect aCatch(SALOME_SalomeException);
217   bool res = false;
218   try {
219     res = _impl->HasShapeToMesh();
220   }
221   catch(SALOME_Exception & S_ex) {
222     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
223   }
224   return res;
225 }
226
227 //================================================================================
228 /*!
229  * \brief Return the shape to mesh
230  */
231 //================================================================================
232
233 GEOM::GEOM_Object_ptr SMESH_Mesh_i::GetShapeToMesh()
234 {
235   Unexpect aCatch(SALOME_SalomeException);
236   GEOM::GEOM_Object_var aShapeObj;
237   try {
238     TopoDS_Shape S = _impl->GetMeshDS()->ShapeToMesh();
239     if ( !S.IsNull() )
240     {
241       aShapeObj = _gen_i->ShapeToGeomObject( S );
242       if ( aShapeObj->_is_nil() )
243       {
244         // S was removed from GEOM_Client by newGroupShape() called by other mesh;
245         // find GEOM_Object by entry (IPAL52735)
246         list<TGeomGroupData>::iterator data = _geomGroupData.begin();
247         for ( ; data != _geomGroupData.end(); ++data )
248           if ( data->_smeshObject->_is_equivalent( _this() ))
249           {
250             SALOMEDS::SObject_wrap so = _gen_i->getStudyServant()->FindObjectID( data->_groupEntry.c_str() );
251             CORBA::Object_var     obj = _gen_i->SObjectToObject( so );
252             aShapeObj = GEOM::GEOM_Object::_narrow( obj );
253             break;
254           }
255       }
256     }
257   }
258   catch(SALOME_Exception & S_ex) {
259     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
260   }
261   return aShapeObj._retn();
262 }
263
264 //================================================================================
265 /*!
266  * \brief Return false if the mesh is not yet fully loaded from the study file
267  */
268 //================================================================================
269
270 CORBA::Boolean SMESH_Mesh_i::IsLoaded()
271 {
272   Unexpect aCatch(SALOME_SalomeException);
273   return !_preMeshInfo;
274 }
275
276 //================================================================================
277 /*!
278  * \brief Load full mesh data from the study file
279  */
280 //================================================================================
281
282 void SMESH_Mesh_i::Load()
283 {
284   Unexpect aCatch(SALOME_SalomeException);
285   if ( _preMeshInfo )
286     _preMeshInfo->FullLoadFromFile();
287 }
288
289 //================================================================================
290 /*!
291  * \brief Remove all nodes and elements
292  */
293 //================================================================================
294
295 void SMESH_Mesh_i::Clear()
296 {
297   Unexpect aCatch(SALOME_SalomeException);
298   if ( _preMeshInfo )
299     _preMeshInfo->ForgetOrLoad(); // load in case if !HasShapeToMesh()
300
301   try {
302     _impl->Clear();
303     //CheckGeomGroupModif(); // issue 20145
304   }
305   catch(SALOME_Exception & S_ex) {
306     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
307   }
308
309   TPythonDump() <<  SMESH::SMESH_Mesh_var(_this()) << ".Clear()";
310
311   SMESH::SMESH_Mesh_var mesh = _this();
312   _gen_i->UpdateIcons( mesh );
313 }
314
315 //================================================================================
316 /*!
317  * \brief Remove all nodes and elements for indicated shape
318  */
319 //================================================================================
320
321 void SMESH_Mesh_i::ClearSubMesh(CORBA::Long ShapeID)
322 {
323   Unexpect aCatch(SALOME_SalomeException);
324   if ( _preMeshInfo )
325     _preMeshInfo->FullLoadFromFile();
326
327   try {
328     _impl->ClearSubMesh( ShapeID );
329   }
330   catch(SALOME_Exception & S_ex) {
331     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
332   }
333   _impl->GetMeshDS()->Modified();
334
335   TPythonDump() <<  SMESH::SMESH_Mesh_var(_this()) << ".ClearSubMesh( " << ShapeID << " )";
336 }
337
338 //=============================================================================
339 /*!
340  * Convert enum Driver_Mesh::Status to SMESH::DriverMED_ReadStatus
341  */
342 //=============================================================================
343
344 static SMESH::DriverMED_ReadStatus ConvertDriverMEDReadStatus (int theStatus)
345 {
346   SMESH::DriverMED_ReadStatus res;
347   switch (theStatus)
348   {
349   case DriverMED_R_SMESHDS_Mesh::DRS_OK:
350     res = SMESH::DRS_OK; break;
351   case DriverMED_R_SMESHDS_Mesh::DRS_EMPTY:
352     res = SMESH::DRS_EMPTY; break;
353   case DriverMED_R_SMESHDS_Mesh::DRS_WARN_RENUMBER:
354     res = SMESH::DRS_WARN_RENUMBER; break;
355   case DriverMED_R_SMESHDS_Mesh::DRS_WARN_SKIP_ELEM:
356     res = SMESH::DRS_WARN_SKIP_ELEM; break;
357   case DriverMED_R_SMESHDS_Mesh::DRS_WARN_DESCENDING:
358     res = SMESH::DRS_WARN_DESCENDING; break;
359   case DriverMED_R_SMESHDS_Mesh::DRS_FAIL:
360   default:
361     res = SMESH::DRS_FAIL; break;
362   }
363   return res;
364 }
365
366 //=============================================================================
367 /*!
368  * Convert ::SMESH_ComputeError to SMESH::ComputeError
369  */
370 //=============================================================================
371
372 static SMESH::ComputeError* ConvertComputeError( SMESH_ComputeErrorPtr errorPtr )
373 {
374   SMESH::ComputeError_var errVar = new SMESH::ComputeError();
375   errVar->subShapeID = -1;
376   errVar->hasBadMesh = false;
377
378   if ( !errorPtr || errorPtr->IsOK() )
379   {
380     errVar->code = SMESH::COMPERR_OK;
381   }
382   else
383   {
384     errVar->code    = ConvertDriverMEDReadStatus( errorPtr->myName );
385     errVar->comment = errorPtr->myComment.c_str();
386   }
387   return errVar._retn();
388 }
389
390 //=============================================================================
391 /*!
392  *  ImportMEDFile
393  *
394  *  Import mesh data from MED file
395  */
396 //=============================================================================
397
398 SMESH::DriverMED_ReadStatus
399 SMESH_Mesh_i::ImportMEDFile( const char* theFileName, const char* theMeshName )
400 {
401   Unexpect aCatch(SALOME_SalomeException);
402   int status;
403   try {
404     status = _impl->MEDToMesh( theFileName, theMeshName );
405   }
406   catch( SALOME_Exception& S_ex ) {
407     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
408   }
409   catch ( ... ) {
410     THROW_SALOME_CORBA_EXCEPTION("ImportMEDFile(): unknown exception", SALOME::BAD_PARAM);
411   }
412
413   CreateGroupServants();
414
415   int major, minor, release;
416   major = minor = release = 0;
417   MED::GetMEDVersion(theFileName, major, minor, release);
418   _medFileInfo           = new SMESH::MedFileInfo();
419   _medFileInfo->fileName = theFileName;
420   _medFileInfo->fileSize = 0;
421   _medFileInfo->major    = major;
422   _medFileInfo->minor    = minor;
423   _medFileInfo->release  = release;
424   _medFileInfo->fileSize = SMESH_File( theFileName ).size();
425
426   return ConvertDriverMEDReadStatus(status);
427 }
428
429 //================================================================================
430 /*!
431  * \brief Import mesh data from the CGNS file
432  */
433 //================================================================================
434
435 SMESH::DriverMED_ReadStatus SMESH_Mesh_i::ImportCGNSFile( const char*  theFileName,
436                                                           const int    theMeshIndex,
437                                                           std::string& theMeshName )
438 {
439   Unexpect aCatch(SALOME_SalomeException);
440   int status;
441   try {
442     status = _impl->CGNSToMesh( theFileName, theMeshIndex, theMeshName );
443   }
444   catch( SALOME_Exception& S_ex ) {
445     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
446   }
447   catch ( ... ) {
448     THROW_SALOME_CORBA_EXCEPTION("ImportCGNSFile(): unknown exception", SALOME::BAD_PARAM);
449   }
450
451   CreateGroupServants();
452
453   _medFileInfo           = new SMESH::MedFileInfo();
454   _medFileInfo->fileName = theFileName;
455   _medFileInfo->major    = 0;
456   _medFileInfo->minor    = 0;
457   _medFileInfo->release  = 0;
458   _medFileInfo->fileSize = SMESH_File( theFileName ).size();
459
460   return ConvertDriverMEDReadStatus(status);
461 }
462
463 //================================================================================
464 /*!
465  * \brief Return string representation of a MED file version comprising nbDigits
466  */
467 //================================================================================
468
469 char* SMESH_Mesh_i::GetVersionString(CORBA::Long minor, CORBA::Short nbDigits)
470 {
471   string ver = DriverMED_W_SMESHDS_Mesh::GetVersionString(minor, nbDigits);
472   return CORBA::string_dup( ver.c_str() );
473 }
474
475 //================================================================================
476 /*!
477  *  Return the list of med versions compatibles for write/append,
478  *  encoded in 10*major+minor (for instance, code for med 3.2.1 is 32)
479  */
480 //================================================================================
481
482 SMESH::long_array* SMESH_Mesh_i::GetMEDVersionsCompatibleForAppend()
483 {
484   SMESH::long_array_var aResult = new SMESH::long_array();
485   std::vector<int> mvok = MED::GetMEDVersionsAppendCompatible();
486   long nbver = mvok.size();
487   aResult->length( nbver );
488   for ( int i = 0; i < nbver; i++ )
489     aResult[i] = mvok[i];
490   return aResult._retn();
491 }
492
493 //=============================================================================
494 /*!
495  *  ImportUNVFile
496  *
497  *  Import mesh data from MED file
498  */
499 //=============================================================================
500
501 int SMESH_Mesh_i::ImportUNVFile( const char* theFileName )
502 {
503   SMESH_TRY;
504
505   // Read mesh with name = <theMeshName> into SMESH_Mesh
506   _impl->UNVToMesh( theFileName );
507
508   CreateGroupServants();
509
510   _medFileInfo           = new SMESH::MedFileInfo();
511   _medFileInfo->fileName = theFileName;
512   _medFileInfo->major    = 0;
513   _medFileInfo->minor    = 0;
514   _medFileInfo->release  = 0;
515   _medFileInfo->fileSize = SMESH_File( theFileName ).size();
516
517   SMESH_CATCH( SMESH::throwCorbaException );
518
519   return 1;
520 }
521
522 //=============================================================================
523 /*!
524  *  ImportSTLFile
525  *
526  *  Import mesh data from STL file
527  */
528 //=============================================================================
529
530 int SMESH_Mesh_i::ImportSTLFile( const char* theFileName )
531 {
532   SMESH_TRY;
533
534   // Read mesh with name = <theMeshName> into SMESH_Mesh
535   std::string name = _impl->STLToMesh( theFileName );
536   if ( !name.empty() )
537   {
538     SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( _this() );
539     _gen_i->SetName( meshSO, name.c_str() );
540   }
541   _medFileInfo           = new SMESH::MedFileInfo();
542   _medFileInfo->fileName = theFileName;
543   _medFileInfo->major    = 0;
544   _medFileInfo->minor    = 0;
545   _medFileInfo->release  = 0;
546   _medFileInfo->fileSize = SMESH_File( theFileName ).size();
547
548   SMESH_CATCH( SMESH::throwCorbaException );
549
550   return 1;
551 }
552
553 //================================================================================
554 /*!
555  * \brief Function used in SMESH_CATCH by ImportGMFFile()
556  */
557 //================================================================================
558
559 namespace
560 {
561   SMESH_ComputeErrorPtr exceptionToComputeError(const char* excText)
562   {
563     return SMESH_ComputeError::New( Driver_Mesh::DRS_FAIL, excText );
564   }
565 }
566
567 //================================================================================
568 /*!
569  * \brief Import data from a GMF file and return an error description
570  */
571 //================================================================================
572
573 SMESH::ComputeError* SMESH_Mesh_i::ImportGMFFile( const char* theFileName,
574                                                   bool        theMakeRequiredGroups )
575 {
576   SMESH_ComputeErrorPtr error;
577
578 #undef SMESH_CAUGHT
579 #define SMESH_CAUGHT error =
580   SMESH_TRY;
581
582   error = _impl->GMFToMesh( theFileName, theMakeRequiredGroups );
583
584   _medFileInfo           = new SMESH::MedFileInfo();
585   _medFileInfo->fileName = theFileName;
586   _medFileInfo->major    = 0;
587   _medFileInfo->minor    = 0;
588   _medFileInfo->release  = 0;
589   _medFileInfo->fileSize = SMESH_File( theFileName ).size();
590
591   SMESH_CATCH( exceptionToComputeError );
592 #undef SMESH_CAUGHT
593 #define SMESH_CAUGHT
594
595   CreateGroupServants();
596
597   return ConvertComputeError( error );
598 }
599
600 //=============================================================================
601 /*!
602  * \brief Convert SMESH_Hypothesis::Hypothesis_Status into SMESH::Hypothesis_Status
603  */
604 //=============================================================================
605
606 #define RETURNCASE(hyp_stat) case SMESH_Hypothesis::hyp_stat: return SMESH::hyp_stat;
607
608 SMESH::Hypothesis_Status SMESH_Mesh_i::ConvertHypothesisStatus
609                          (SMESH_Hypothesis::Hypothesis_Status theStatus)
610 {
611   switch (theStatus) {
612   RETURNCASE( HYP_OK            );
613   RETURNCASE( HYP_MISSING       );
614   RETURNCASE( HYP_CONCURRENT    );
615   RETURNCASE( HYP_BAD_PARAMETER );
616   RETURNCASE( HYP_HIDDEN_ALGO   );
617   RETURNCASE( HYP_HIDING_ALGO   );
618   RETURNCASE( HYP_UNKNOWN_FATAL );
619   RETURNCASE( HYP_INCOMPATIBLE  );
620   RETURNCASE( HYP_NOTCONFORM    );
621   RETURNCASE( HYP_ALREADY_EXIST );
622   RETURNCASE( HYP_BAD_DIM       );
623   RETURNCASE( HYP_BAD_SUBSHAPE  );
624   RETURNCASE( HYP_BAD_GEOMETRY  );
625   RETURNCASE( HYP_NEED_SHAPE    );
626   RETURNCASE( HYP_INCOMPAT_HYPS );
627   default:;
628   }
629   return SMESH::HYP_UNKNOWN_FATAL;
630 }
631
632 //=============================================================================
633 /*!
634  *  AddHypothesis
635  *
636  *  Call internal addHypothesis() and then add a reference to <anHyp> under
637  *  the SObject actually having a reference to <aSubShape>.
638  *  NB: For this method to work, it is necessary to add a reference to sub-shape first.
639  */
640 //=============================================================================
641
642 SMESH::Hypothesis_Status
643 SMESH_Mesh_i::AddHypothesis(GEOM::GEOM_Object_ptr       aSubShape,
644                             SMESH::SMESH_Hypothesis_ptr anHyp,
645                             CORBA::String_out           anErrorText)
646 {
647   Unexpect aCatch(SALOME_SalomeException);
648
649   const smIdType prevNbMeshEnt = NbNodes() + NbElements();
650
651   if ( _preMeshInfo )
652     _preMeshInfo->ForgetOrLoad();
653
654   std::string error;
655   SMESH_Hypothesis::Hypothesis_Status status = addHypothesis( aSubShape, anHyp, &error );
656   anErrorText = error.c_str();
657
658   SMESH::SMESH_Mesh_var mesh( _this() );
659   if ( !SMESH_Hypothesis::IsStatusFatal(status) )
660   {
661     _gen_i->AddHypothesisToShape( mesh, aSubShape, anHyp );
662
663     //int newNbMeshEnt = _impl->NbNodes() + _impl->GetMeshDS()->NbElements();
664     if ( prevNbMeshEnt > 0 /*newNbMeshEnt != prevNbMeshEnt*/ )
665       _gen_i->UpdateIcons( mesh );
666   }
667   if(MYDEBUG) MESSAGE( " AddHypothesis(): status = " << status );
668
669   // Update Python script
670   TPythonDump() << "status = " << mesh << ".AddHypothesis( "
671                 << aSubShape << ", " << anHyp << " )";
672
673   return ConvertHypothesisStatus(status);
674 }
675
676 //================================================================================
677 /*!
678  * \brief Create  a sub-mesh and add a hypothesis to it
679  */
680 //================================================================================
681
682 SMESH_Hypothesis::Hypothesis_Status
683 SMESH_Mesh_i::addHypothesis(GEOM::GEOM_Object_ptr       aSubShape,
684                             SMESH::SMESH_Hypothesis_ptr anHyp,
685                             std::string*                anErrorText)
686 {
687   if(MYDEBUG) MESSAGE("addHypothesis");
688
689   if (CORBA::is_nil( aSubShape ) && HasShapeToMesh())
690     THROW_SALOME_CORBA_EXCEPTION("bad Sub-shape reference",SALOME::BAD_PARAM);
691
692   if (CORBA::is_nil( anHyp ))
693     THROW_SALOME_CORBA_EXCEPTION("bad hypothesis reference",SALOME::BAD_PARAM);
694
695   SMESH_Hypothesis::Hypothesis_Status status = SMESH_Hypothesis::HYP_OK;
696   try
697   {
698     TopoDS_Shape myLocSubShape;
699     //use PseudoShape in case if mesh has no shape
700     if(HasShapeToMesh())
701       myLocSubShape = _gen_i->GeomObjectToShape( aSubShape);
702     else
703       myLocSubShape = _impl->GetShapeToMesh();
704
705     const int hypId = anHyp->GetId();
706     std::string error;
707     status = _impl->AddHypothesis( myLocSubShape, hypId, &error );
708     if ( !SMESH_Hypothesis::IsStatusFatal(status) )
709     {
710       _mapHypo[hypId] = SMESH::SMESH_Hypothesis::_duplicate( anHyp );
711       anHyp->Register();
712       // assure there is a corresponding submesh
713       if ( !_impl->IsMainShape( myLocSubShape )) {
714         int shapeId = _impl->GetMeshDS()->ShapeToIndex( myLocSubShape );
715         if ( _mapSubMesh_i.find( shapeId ) == _mapSubMesh_i.end() )
716           SMESH::SMESH_subMesh_var( createSubMesh( aSubShape ));
717       }
718     }
719     else if ( anErrorText )
720     {
721       *anErrorText = error;
722     }
723   }
724   catch(SALOME_Exception & S_ex)
725   {
726     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
727   }
728   return status;
729 }
730
731 //================================================================================
732 /*!
733  * \brief Un-assign a hypothesis from a sub-mesh dedicate to the given sub-shape
734  */
735 //================================================================================
736
737 SMESH::Hypothesis_Status SMESH_Mesh_i::RemoveHypothesis(GEOM::GEOM_Object_ptr       aSubShape,
738                                                         SMESH::SMESH_Hypothesis_ptr anHyp)
739 {
740   Unexpect aCatch(SALOME_SalomeException);
741   if ( _preMeshInfo )
742     _preMeshInfo->ForgetOrLoad();
743
744   SMESH_Hypothesis::Hypothesis_Status status = removeHypothesis( aSubShape, anHyp );
745   SMESH::SMESH_Mesh_var mesh = _this();
746
747   if ( !SMESH_Hypothesis::IsStatusFatal(status) )
748   {
749     _gen_i->RemoveHypothesisFromShape( mesh, aSubShape, anHyp );
750     _gen_i->UpdateIcons( mesh );
751   }
752   // Update Python script
753   if(_impl->HasShapeToMesh())
754     TPythonDump() << "status = " << mesh << ".RemoveHypothesis( "
755                   << aSubShape << ", " << anHyp << " )";
756   else
757     TPythonDump() << "status = " << mesh << ".RemoveHypothesis( "
758                   << anHyp << " )";
759
760   return ConvertHypothesisStatus(status);
761 }
762
763 //=============================================================================
764 /*!
765  * \brief Un-assign a hypothesis from a sub-mesh dedicate to the given sub-shape
766  */
767 //=============================================================================
768
769 SMESH_Hypothesis::Hypothesis_Status
770 SMESH_Mesh_i::removeHypothesis(GEOM::GEOM_Object_ptr       aSubShape,
771                                SMESH::SMESH_Hypothesis_ptr anHyp)
772 {
773   if(MYDEBUG) MESSAGE("removeHypothesis()");
774
775   if (CORBA::is_nil( aSubShape ) && HasShapeToMesh())
776     THROW_SALOME_CORBA_EXCEPTION("bad Sub-shape reference", SALOME::BAD_PARAM);
777
778   if (CORBA::is_nil( anHyp ))
779     THROW_SALOME_CORBA_EXCEPTION("bad hypothesis reference", SALOME::BAD_PARAM);
780
781   if ( _preMeshInfo )
782     _preMeshInfo->ForgetOrLoad();
783
784   SMESH_Hypothesis::Hypothesis_Status status = SMESH_Hypothesis::HYP_OK;
785   try
786   {
787     TopoDS_Shape myLocSubShape;
788     //use PseudoShape in case if mesh has no shape
789     if( _impl->HasShapeToMesh() )
790       myLocSubShape = _gen_i->GeomObjectToShape( aSubShape );
791     else
792       myLocSubShape = _impl->GetShapeToMesh();
793
794     const int hypId = anHyp->GetId();
795     status = _impl->RemoveHypothesis(myLocSubShape, hypId);
796     if ( !SMESH_Hypothesis::IsStatusFatal(status) )
797     {
798       // _mapHypo.erase( hypId ); EAP: hyp can be used on many sub-shapes
799       anHyp->UnRegister();
800     }
801   }
802   catch(SALOME_Exception & S_ex)
803   {
804     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
805   }
806   return status;
807 }
808
809 //================================================================================
810 /*!
811  * \brief Return hypotheses assigned to a given sub-shape
812  */
813 //================================================================================
814
815 SMESH::ListOfHypothesis *
816 SMESH_Mesh_i::GetHypothesisList(GEOM::GEOM_Object_ptr aSubShape)
817 {
818   Unexpect aCatch(SALOME_SalomeException);
819   if (MYDEBUG) MESSAGE("GetHypothesisList");
820   if (_impl->HasShapeToMesh() && CORBA::is_nil(aSubShape))
821     THROW_SALOME_CORBA_EXCEPTION("bad Sub-shape reference", SALOME::BAD_PARAM);
822
823   SMESH::ListOfHypothesis_var aList = new SMESH::ListOfHypothesis();
824
825   try {
826     TopoDS_Shape myLocSubShape = _gen_i->GeomObjectToShape(aSubShape);
827     if ( myLocSubShape.IsNull() && !_impl->HasShapeToMesh() )
828       myLocSubShape = _impl->GetShapeToMesh();
829     const list<const SMESHDS_Hypothesis*>& aLocalList = _impl->GetHypothesisList( myLocSubShape );
830     int i = 0, n = aLocalList.size();
831     aList->length( n );
832
833     list<const SMESHDS_Hypothesis*>::const_iterator aHyp = aLocalList.begin();
834     std::map<int, SMESH::SMESH_Hypothesis_ptr>::iterator id_hypptr;
835     for ( ; i < n && aHyp != aLocalList.end(); aHyp++ )
836     {
837       id_hypptr = _mapHypo.find( (*aHyp)->GetID() );
838       if ( id_hypptr != _mapHypo.end() )
839         aList[i++] = SMESH::SMESH_Hypothesis::_narrow( id_hypptr->second );
840     }
841     aList->length( i );
842   }
843   catch(SALOME_Exception & S_ex) {
844     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
845   }
846
847   return aList._retn();
848 }
849
850 //================================================================================
851 /*!
852  * \brief Return sub-meshes
853  */
854 //================================================================================
855
856 SMESH::submesh_array* SMESH_Mesh_i::GetSubMeshes()
857 {
858   Unexpect aCatch(SALOME_SalomeException);
859   if (MYDEBUG) MESSAGE("GetSubMeshes");
860
861   SMESH::submesh_array_var aList = new SMESH::submesh_array();
862
863   // Python Dump
864   TPythonDump aPythonDump;
865   if ( !_mapSubMeshIor.empty() )
866     aPythonDump << "[ ";
867
868   try {
869     aList->length( _mapSubMeshIor.size() );
870     int i = 0;
871     map<int, SMESH::SMESH_subMesh_ptr>::iterator it = _mapSubMeshIor.begin();
872     for ( ; it != _mapSubMeshIor.end(); it++ ) {
873       if ( CORBA::is_nil( it->second )) continue;
874       aList[i++] = SMESH::SMESH_subMesh::_duplicate( it->second );
875       // Python Dump
876       if (i > 1) aPythonDump << ", ";
877       aPythonDump << it->second;
878     }
879     aList->length( i );
880   }
881   catch(SALOME_Exception & S_ex) {
882     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
883   }
884
885   // Update Python script
886   if ( !_mapSubMeshIor.empty() )
887     aPythonDump << " ] = " << SMESH::SMESH_Mesh_var( _this() ) << ".GetSubMeshes()";
888
889   return aList._retn();
890 }
891
892 //================================================================================
893 /*!
894  * \brief Create and return a sub-mesh on the given sub-shape
895  */
896 //================================================================================
897
898 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::GetSubMesh(GEOM::GEOM_Object_ptr aSubShape,
899                                                   const char*           theName )
900 {
901   Unexpect aCatch(SALOME_SalomeException);
902   if (CORBA::is_nil(aSubShape))
903     THROW_SALOME_CORBA_EXCEPTION("bad Sub-shape reference", SALOME::BAD_PARAM);
904
905   SMESH::SMESH_subMesh_var subMesh;
906   SMESH::SMESH_Mesh_var    aMesh = _this();
907   try {
908     TopoDS_Shape myLocSubShape = _gen_i->GeomObjectToShape(aSubShape);
909
910     //Get or Create the SMESH_subMesh object implementation
911
912     TopoDS_Iterator it( myLocSubShape );
913     int   subMeshId = _impl->GetMeshDS()->ShapeToIndex( myLocSubShape );
914     bool isValidSub = ( subMeshId || _impl->GetMeshDS()->IsGroupOfSubShapes( myLocSubShape ));
915     if ( isValidSub && myLocSubShape.ShapeType() == TopAbs_COMPOUND )
916       isValidSub = !it.Value().IsSame( _impl->GetShapeToMesh() );
917     if ( !isValidSub )
918     {
919       if ( it.More() )
920         THROW_SALOME_CORBA_EXCEPTION("Not a sub-shape of the main shape", SALOME::BAD_PARAM);
921     }
922     subMesh = getSubMesh( subMeshId );
923
924     // create a new subMesh object servant if there is none for the shape
925     if ( subMesh->_is_nil() )
926       subMesh = createSubMesh( aSubShape );
927     if ( _gen_i->CanPublishInStudy( subMesh ))
928     {
929       SALOMEDS::SObject_wrap aSO =
930         _gen_i->PublishSubMesh( aMesh, subMesh, aSubShape, theName );
931       if ( !aSO->_is_nil()) {
932         // Update Python script
933         TPythonDump() << aSO << " = " << aMesh << ".GetSubMesh( "
934                       << aSubShape << ", '" << theName << "' )";
935       }
936     }
937   }
938   catch(SALOME_Exception & S_ex) {
939     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
940   }
941   return subMesh._retn();
942 }
943
944 //================================================================================
945 /*!
946  * \brief Remove a sub-mesh
947  */
948 //================================================================================
949
950 void SMESH_Mesh_i::RemoveSubMesh( SMESH::SMESH_subMesh_ptr theSubMesh )
951 {
952   SMESH_TRY;
953
954   if ( theSubMesh->_is_nil() )
955     return;
956
957   GEOM::GEOM_Object_var aSubShape;
958   // Remove submesh's SObject
959   SALOMEDS::SObject_wrap anSO = _gen_i->ObjectToSObject( theSubMesh );
960   if ( !anSO->_is_nil() ) {
961     long aTag = SMESH_Gen_i::GetRefOnShapeTag();
962     SALOMEDS::SObject_wrap anObj, aRef;
963     if ( anSO->FindSubObject( aTag, anObj.inout() ) &&
964          anObj->ReferencedObject( aRef.inout() ))
965     {
966       CORBA::Object_var obj = aRef->GetObject();
967       aSubShape = GEOM::GEOM_Object::_narrow( obj );
968     }
969     // if ( aSubShape->_is_nil() ) // not published shape (IPAL13617)
970     //   aSubShape = theSubMesh->GetSubShape();
971
972     SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
973     builder->RemoveObjectWithChildren( anSO );
974
975     // Update Python script
976     TPythonDump() << SMESH::SMESH_Mesh_var( _this() ) << ".RemoveSubMesh( " << anSO << " )";
977   }
978
979   if ( removeSubMesh( theSubMesh, aSubShape.in() ))
980     if ( _preMeshInfo )
981       _preMeshInfo->ForgetOrLoad();
982
983   SMESH_CATCH( SMESH::throwCorbaException );
984 }
985
986 //================================================================================
987 /*!
988  * \brief Create a standalone group
989  */
990 //================================================================================
991
992 SMESH::SMESH_Group_ptr SMESH_Mesh_i::CreateGroup( SMESH::ElementType theElemType,
993                                                   const char*        theName )
994 {
995   Unexpect aCatch(SALOME_SalomeException);
996   if ( _preMeshInfo )
997     _preMeshInfo->FullLoadFromFile();
998
999   SMESH::SMESH_Group_var aNewGroup =
1000     SMESH::SMESH_Group::_narrow( createGroup( theElemType, theName ));
1001
1002   if ( _gen_i->CanPublishInStudy( aNewGroup ) )
1003   {
1004     SMESH::SMESH_Mesh_var mesh = _this();
1005     SALOMEDS::SObject_wrap aSO =
1006       _gen_i->PublishGroup( mesh, aNewGroup, GEOM::GEOM_Object::_nil(), theName);
1007     if ( !aSO->_is_nil())
1008       // Update Python script
1009       TPythonDump() << aSO << " = " << mesh << ".CreateGroup( "
1010                     << theElemType << ", '" << theName << "' )";
1011   }
1012   return aNewGroup._retn();
1013 }
1014
1015 //================================================================================
1016 /*!
1017  * \brief Create a group based on the given geometry
1018  */
1019 //================================================================================
1020
1021 SMESH::SMESH_GroupOnGeom_ptr
1022 SMESH_Mesh_i::CreateGroupFromGEOM (SMESH::ElementType    theElemType,
1023                                    const char*           theName,
1024                                    GEOM::GEOM_Object_ptr theGeomObj)
1025 {
1026   Unexpect aCatch(SALOME_SalomeException);
1027   if ( _preMeshInfo )
1028     _preMeshInfo->FullLoadFromFile();
1029
1030   SMESH::SMESH_GroupOnGeom_var aNewGroup;
1031
1032   TopoDS_Shape aShape = _gen_i->GeomObjectToShape( theGeomObj );
1033   if ( !aShape.IsNull() )
1034   {
1035     aNewGroup =
1036       SMESH::SMESH_GroupOnGeom::_narrow( createGroup( theElemType, theName, /*id=*/-1, aShape ));
1037
1038     if ( _gen_i->CanPublishInStudy( aNewGroup ) )
1039     {
1040       SMESH::SMESH_Mesh_var mesh = _this();
1041       SALOMEDS::SObject_wrap aSO =
1042         _gen_i->PublishGroup( mesh, aNewGroup, theGeomObj, theName );
1043       if ( !aSO->_is_nil())
1044         TPythonDump() << aSO << " = " << mesh << ".CreateGroupFromGEOM( "
1045                       << theElemType << ", '" << theName << "', " << theGeomObj << " )";
1046     }
1047   }
1048
1049   return aNewGroup._retn();
1050 }
1051
1052 //================================================================================
1053 /*!
1054  * \brief Creates a group whose contents is defined by filter
1055  *  \param theElemType - group type
1056  *  \param theName - group name
1057  *  \param theFilter - the filter
1058  *  \retval SMESH::SMESH_GroupOnFilter_ptr - group defined by filter
1059  */
1060 //================================================================================
1061
1062 SMESH::SMESH_GroupOnFilter_ptr
1063 SMESH_Mesh_i::CreateGroupFromFilter(SMESH::ElementType theElemType,
1064                                     const char*        theName,
1065                                     SMESH::Filter_ptr  theFilter )
1066 {
1067   Unexpect aCatch(SALOME_SalomeException);
1068   if ( _preMeshInfo )
1069     _preMeshInfo->FullLoadFromFile();
1070
1071   if ( CORBA::is_nil( theFilter ))
1072     THROW_SALOME_CORBA_EXCEPTION("NULL filter", SALOME::BAD_PARAM);
1073
1074   SMESH_PredicatePtr predicate = SMESH_GroupOnFilter_i::GetPredicate( theFilter );
1075   if ( !predicate )
1076     THROW_SALOME_CORBA_EXCEPTION("Invalid filter", SALOME::BAD_PARAM);
1077
1078   SMESH::SMESH_GroupOnFilter_var aNewGroup = SMESH::SMESH_GroupOnFilter::_narrow
1079     ( createGroup( theElemType, theName, /*id=*/-1, TopoDS_Shape(), predicate ));
1080
1081   TPythonDump pd;
1082   if ( !aNewGroup->_is_nil() )
1083     aNewGroup->SetFilter( theFilter );
1084
1085   if ( _gen_i->CanPublishInStudy( aNewGroup ) )
1086   {
1087     SMESH::SMESH_Mesh_var mesh = _this();
1088     SALOMEDS::SObject_wrap aSO =
1089       _gen_i->PublishGroup( mesh, aNewGroup, GEOM::GEOM_Object::_nil(), theName );
1090
1091     if ( !aSO->_is_nil())
1092       pd << aSO << " = " << mesh << ".CreateGroupFromFilter( "
1093          << theElemType << ", '" << theName << "', " << theFilter << " )";
1094   }
1095   return aNewGroup._retn();
1096 }
1097
1098 //================================================================================
1099 /*!
1100  * \brief Remove a group
1101  */
1102 //================================================================================
1103
1104 void SMESH_Mesh_i::RemoveGroup( SMESH::SMESH_GroupBase_ptr theGroup )
1105 {
1106   if ( theGroup->_is_nil() )
1107     return;
1108
1109   SMESH_TRY;
1110
1111   SMESH_GroupBase_i* aGroup = SMESH::DownCast<SMESH_GroupBase_i*>( theGroup );
1112   if ( !aGroup )
1113     return;
1114
1115   if ( aGroup->GetMeshServant() != this )
1116     THROW_SALOME_CORBA_EXCEPTION( "RemoveGroup(): group does not belong to this mesh",
1117                                   SALOME::BAD_PARAM );
1118
1119   SALOMEDS::SObject_wrap aGroupSO = _gen_i->ObjectToSObject( theGroup );
1120   if ( !aGroupSO->_is_nil() )
1121   {
1122     // Update Python script
1123     TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".RemoveGroup( " << aGroupSO << " )";
1124
1125     // Remove group's SObject
1126     SALOMEDS::StudyBuilder_var builder = SMESH_Gen_i::GetSMESHGen()->getStudyServant()->NewBuilder();
1127     builder->RemoveObjectWithChildren( aGroupSO );
1128   }
1129   aGroup->Modified(/*removed=*/true); // notify dependent Filter with FT_BelongToMeshGroup criterion
1130
1131   // Remove the group from SMESH data structures
1132   removeGroup( aGroup->GetLocalID() );
1133
1134   SMESH_CATCH( SMESH::throwCorbaException );
1135 }
1136
1137 //=============================================================================
1138 /*!
1139  *  Remove group with its contents
1140  */
1141 //=============================================================================
1142
1143 void SMESH_Mesh_i::RemoveGroupWithContents( SMESH::SMESH_GroupBase_ptr theGroup )
1144 {
1145   SMESH_TRY;
1146   if ( _preMeshInfo )
1147     _preMeshInfo->FullLoadFromFile();
1148
1149   if ( theGroup->_is_nil() )
1150     return;
1151
1152   SMESH_GroupBase_i* groupImpl = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup );
1153   if ( !groupImpl || groupImpl->GetMeshServant() != this )
1154     THROW_SALOME_CORBA_EXCEPTION( "RemoveGroupWithContents(): group does not belong to this mesh",
1155                                   SALOME::BAD_PARAM);
1156
1157   vector<smIdType> nodeIds; // to remove nodes becoming free
1158   bool isNodal = ( theGroup->GetType() == SMESH::NODE );
1159   if ( !isNodal && !theGroup->IsEmpty() )
1160   {
1161     SMESH::smIdType elemID = theGroup->GetID( 1 );
1162     int nbElemNodes = GetElemNbNodes( elemID );
1163     if ( nbElemNodes > 0 )
1164       nodeIds.reserve( theGroup->Size() * nbElemNodes );
1165   }
1166
1167   // Retrieve contents
1168   SMESH::SMESH_IDSource_var idSrc = SMESH::SMESH_IDSource::_narrow( theGroup );
1169   SMDS_ElemIteratorPtr     elemIt = GetElements( idSrc, theGroup->GetType() );
1170   SMDS_StdIterator< const SMDS_MeshElement*, SMDS_ElemIteratorPtr > elemBeg( elemIt ), elemEnd;
1171   std::vector< const SMDS_MeshElement* > elems( theGroup->Size() );
1172   elems.assign( elemBeg, elemEnd );
1173
1174   TPythonDump pyDump; // Suppress dump from RemoveGroup()
1175
1176   // Remove group
1177   RemoveGroup( theGroup );
1178
1179   // Remove contents
1180   for ( size_t i = 0; i < elems.size(); ++i )
1181   {
1182     // if ( !_impl->GetMeshDS()->Contains( elems[i] ))
1183     //   continue;
1184     if ( !isNodal )
1185     {
1186       for ( SMDS_ElemIteratorPtr nIt = elems[i]->nodesIterator(); nIt->more(); )
1187         nodeIds.push_back( nIt->next()->GetID() );
1188
1189       _impl->GetMeshDS()->RemoveFreeElement( elems[i], /*sm=*/0 );
1190     }
1191     else
1192     {
1193       _impl->GetMeshDS()->RemoveElement( elems[i] );
1194     }
1195   }
1196
1197   // Remove free nodes
1198   for ( size_t i = 0 ; i < nodeIds.size(); ++i )
1199     if ( const SMDS_MeshNode* n = _impl->GetMeshDS()->FindNode( nodeIds[i] ))
1200       if ( n->NbInverseElements() == 0 )
1201         _impl->GetMeshDS()->RemoveFreeNode( n, /*sm=*/0 );
1202
1203   _impl->GetMeshDS()->Modified();
1204   _impl->SetIsModified( true );
1205
1206   // Update Python script (theGroup must be alive for this)
1207   pyDump << SMESH::SMESH_Mesh_var(_this())
1208          << ".RemoveGroupWithContents( " << theGroup << " )";
1209
1210   SMESH_CATCH( SMESH::throwCorbaException );
1211 }
1212
1213 //================================================================================
1214 /*!
1215  * \brief Get the list of groups existing in the mesh
1216  *  \retval SMESH::ListOfGroups * - list of groups
1217  */
1218 //================================================================================
1219
1220 SMESH::ListOfGroups * SMESH_Mesh_i::GetGroups()
1221 {
1222   Unexpect aCatch(SALOME_SalomeException);
1223   if (MYDEBUG) MESSAGE("GetGroups");
1224
1225   SMESH::ListOfGroups_var aList = new SMESH::ListOfGroups();
1226
1227   // Python Dump
1228   TPythonDump aPythonDump;
1229   if ( !_mapGroups.empty() )
1230   {
1231     aPythonDump << "[ ";
1232     try {
1233       aList->length( _mapGroups.size() );
1234       int i = 0;
1235       map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.begin();
1236       for ( ; it != _mapGroups.end(); it++ ) {
1237         if ( CORBA::is_nil( it->second )) continue;
1238         aList[i++] = SMESH::SMESH_GroupBase::_duplicate( it->second );
1239         // Python Dump
1240         if (i > 1) aPythonDump << ", ";
1241         aPythonDump << it->second;
1242       }
1243       aList->length( i );
1244     }
1245     catch(SALOME_Exception & S_ex) {
1246       THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
1247     }
1248     aPythonDump << " ] = " << SMESH::SMESH_Mesh_var(_this()) << ".GetGroups()";
1249   }
1250   return aList._retn();
1251 }
1252
1253 //=============================================================================
1254 /*!
1255  *  Get number of groups existing in the mesh
1256  */
1257 //=============================================================================
1258
1259 CORBA::Long SMESH_Mesh_i::NbGroups()
1260 {
1261   Unexpect aCatch(SALOME_SalomeException);
1262   return _mapGroups.size();
1263 }
1264
1265 //=============================================================================
1266 /*!
1267  * New group including all mesh elements present in initial groups is created.
1268  */
1269 //=============================================================================
1270
1271 SMESH::SMESH_Group_ptr SMESH_Mesh_i::UnionGroups( SMESH::SMESH_GroupBase_ptr theGroup1,
1272                                                   SMESH::SMESH_GroupBase_ptr theGroup2,
1273                                                   const char*                theName )
1274 {
1275   SMESH::SMESH_Group_var aResGrp;
1276
1277   SMESH_TRY;
1278   if ( _preMeshInfo )
1279     _preMeshInfo->FullLoadFromFile();
1280
1281   if ( theGroup1->_is_nil() || theGroup2->_is_nil() )
1282     THROW_SALOME_CORBA_EXCEPTION("UnionGroups(): NULL Group",
1283                                  SALOME::BAD_PARAM);
1284   if ( theGroup1->GetType() != theGroup2->GetType() )
1285     THROW_SALOME_CORBA_EXCEPTION("UnionGroups(): different group types",
1286                                  SALOME::BAD_PARAM);
1287   TPythonDump pyDump;
1288
1289   // Create Union
1290   aResGrp = CreateGroup( theGroup1->GetType(), theName );
1291   if ( aResGrp->_is_nil() )
1292     return SMESH::SMESH_Group::_nil();
1293
1294   aResGrp->AddFrom( theGroup1 );
1295   aResGrp->AddFrom( theGroup2 );
1296
1297   // Update Python script
1298   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var(_this())
1299          << ".UnionGroups( " << theGroup1 << ", " << theGroup2 << ", '" << theName << "' )";
1300
1301   SMESH_CATCH( SMESH::throwCorbaException );
1302
1303   return aResGrp._retn();
1304 }
1305
1306 //=============================================================================
1307 /*!
1308  * \brief New group including all mesh elements present in initial groups is created.
1309  *  \param theGroups list of groups
1310  *  \param theName name of group to be created
1311  *  \return pointer to the new group
1312  */
1313 //=============================================================================
1314
1315 SMESH::SMESH_Group_ptr SMESH_Mesh_i::UnionListOfGroups(const SMESH::ListOfGroups& theGroups,
1316                                                        const char*                theName )
1317 {
1318   SMESH::SMESH_Group_var aResGrp;
1319
1320   if ( _preMeshInfo )
1321     _preMeshInfo->FullLoadFromFile();
1322
1323   if ( !theName )
1324     return SMESH::SMESH_Group::_nil();
1325
1326   SMESH_TRY;
1327
1328   // check types
1329   SMESH::ElementType aType = SMESH::ALL;
1330   for ( int g = 0, n = theGroups.length(); g < n; g++ )
1331   {
1332     SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ];
1333     if ( CORBA::is_nil( aGrp ) )
1334       continue;
1335     if ( aType == SMESH::ALL )
1336       aType = aGrp->GetType();
1337     else if ( aType != aGrp->GetType() )
1338       THROW_SALOME_CORBA_EXCEPTION("UnionListOfGroups(): different group types",
1339                                    SALOME::BAD_PARAM);
1340   }
1341   if ( aType == SMESH::ALL )
1342     return SMESH::SMESH_Group::_nil();
1343
1344   TPythonDump pyDump;
1345
1346   // Create Union
1347   aResGrp = CreateGroup( aType, theName );
1348   if ( aResGrp->_is_nil() )
1349     return SMESH::SMESH_Group::_nil();
1350
1351   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var(_this()) << ".UnionListOfGroups([ ";
1352   for ( int g = 0, n = theGroups.length(); g < n; g++ )
1353   {
1354     SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ];
1355     if ( !CORBA::is_nil( aGrp ) )
1356     {
1357       aResGrp->AddFrom( aGrp );
1358       if ( g > 0 ) pyDump << ", ";
1359       pyDump << aGrp;
1360     }
1361   }
1362   pyDump << " ], '" << theName << "' )";
1363
1364   SMESH_CATCH( SMESH::throwCorbaException );
1365
1366   return aResGrp._retn();
1367 }
1368
1369 //=============================================================================
1370 /*!
1371  *  New group is created. All mesh elements that are
1372  *  present in both initial groups are added to the new one.
1373  */
1374 //=============================================================================
1375
1376 SMESH::SMESH_Group_ptr SMESH_Mesh_i::IntersectGroups( SMESH::SMESH_GroupBase_ptr theGroup1,
1377                                                       SMESH::SMESH_GroupBase_ptr theGroup2,
1378                                                       const char*                theName )
1379 {
1380   SMESH::SMESH_Group_var aResGrp;
1381
1382   SMESH_TRY;
1383
1384   if ( _preMeshInfo )
1385     _preMeshInfo->FullLoadFromFile();
1386
1387   if ( theGroup1->_is_nil() || theGroup2->_is_nil() )
1388     THROW_SALOME_CORBA_EXCEPTION("IntersectGroups(): NULL Group",
1389                                  SALOME::BAD_PARAM);
1390   if ( theGroup1->GetType() != theGroup2->GetType() )
1391     THROW_SALOME_CORBA_EXCEPTION("IntersectGroups(): different group types",
1392                                  SALOME::BAD_PARAM);
1393   TPythonDump pyDump;
1394
1395   // Create Intersection
1396   aResGrp = CreateGroup( theGroup1->GetType(), theName );
1397   if ( aResGrp->_is_nil() )
1398     return aResGrp._retn();
1399
1400   SMESHDS_GroupBase* groupDS1 = 0;
1401   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup1 ))
1402     groupDS1 = grp_i->GetGroupDS();
1403
1404   SMESHDS_GroupBase* groupDS2 = 0;
1405   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup2 ))
1406     groupDS2 = grp_i->GetGroupDS();
1407
1408   SMESHDS_Group* resGroupDS = 0;
1409   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aResGrp ))
1410     resGroupDS = dynamic_cast<SMESHDS_Group*>( grp_i->GetGroupDS() );
1411
1412   if ( groupDS1 && groupDS2 && resGroupDS && !groupDS2->IsEmpty() )
1413   {
1414     SMDS_ElemIteratorPtr elemIt1 = groupDS1->GetElements();
1415     while ( elemIt1->more() )
1416     {
1417       const SMDS_MeshElement* e = elemIt1->next();
1418       if ( groupDS2->Contains( e ))
1419         resGroupDS->SMDSGroup().Add( e );
1420     }
1421   }
1422   // Update Python script
1423   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var(_this()) << ".IntersectGroups( "
1424          << theGroup1 << ", " << theGroup2 << ", '" << theName << "')";
1425
1426   SMESH_CATCH( SMESH::throwCorbaException );
1427
1428   return aResGrp._retn();
1429 }
1430
1431 //=============================================================================
1432 /*!
1433   \brief Intersect list of groups. New group is created. All mesh elements that
1434   are present in all initial groups simultaneously are added to the new one.
1435   \param theGroups list of groups
1436   \param theName name of group to be created
1437   \return pointer on the group
1438 */
1439 //=============================================================================
1440
1441 SMESH::SMESH_Group_ptr
1442 SMESH_Mesh_i::IntersectListOfGroups(const SMESH::ListOfGroups& theGroups,
1443                                     const char*                theName )
1444 {
1445   SMESH::SMESH_Group_var aResGrp;
1446
1447   SMESH_TRY;
1448
1449   if ( _preMeshInfo )
1450     _preMeshInfo->FullLoadFromFile();
1451
1452   if ( !theName )
1453     return SMESH::SMESH_Group::_nil();
1454
1455   // check types and get SMESHDS_GroupBase's
1456   SMESH::ElementType aType = SMESH::ALL;
1457   vector< SMESHDS_GroupBase* > groupVec;
1458   for ( int g = 0, n = theGroups.length(); g < n; g++ )
1459   {
1460     SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ];
1461     if ( CORBA::is_nil( aGrp ) )
1462       continue;
1463     if ( aType == SMESH::ALL )
1464       aType = aGrp->GetType();
1465     else if ( aType != aGrp->GetType() )
1466       THROW_SALOME_CORBA_EXCEPTION("IntersectListOfGroups(): different group types",
1467                                    SALOME::BAD_PARAM);
1468
1469     if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aGrp ))
1470       if ( SMESHDS_GroupBase* grpDS = grp_i->GetGroupDS() )
1471       {
1472         if ( grpDS->IsEmpty() )
1473         {
1474           groupVec.clear();
1475           break;
1476         }
1477         groupVec.push_back( grpDS );
1478       }
1479   }
1480   if ( aType == SMESH::ALL ) // all groups are nil
1481     return SMESH::SMESH_Group::_nil();
1482
1483   TPythonDump pyDump;
1484
1485   // Create a group
1486   aResGrp = CreateGroup( aType, theName );
1487
1488   SMESHDS_Group* resGroupDS = 0;
1489   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aResGrp ))
1490     resGroupDS = dynamic_cast<SMESHDS_Group*>( grp_i->GetGroupDS() );
1491   if ( !resGroupDS || groupVec.empty() )
1492     return aResGrp._retn();
1493
1494   // Fill the group
1495   size_t i, nb = groupVec.size();
1496   SMDS_ElemIteratorPtr elemIt1 = groupVec[0]->GetElements();
1497   while ( elemIt1->more() )
1498   {
1499     const SMDS_MeshElement* e = elemIt1->next();
1500     bool inAll = true;
1501     for ( i = 1; ( i < nb && inAll ); ++i )
1502       inAll = groupVec[i]->Contains( e );
1503
1504     if ( inAll )
1505       resGroupDS->SMDSGroup().Add( e );
1506   }
1507
1508   // Update Python script
1509   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var( _this() )
1510          << ".IntersectListOfGroups( " << theGroups << ", '" << theName << "' )";
1511
1512   SMESH_CATCH( SMESH::throwCorbaException );
1513
1514   return aResGrp._retn();
1515 }
1516
1517 //=============================================================================
1518 /*!
1519  *  New group is created. All mesh elements that are present in
1520  *  a main group but is not present in a tool group are added to the new one
1521  */
1522 //=============================================================================
1523
1524 SMESH::SMESH_Group_ptr SMESH_Mesh_i::CutGroups( SMESH::SMESH_GroupBase_ptr theGroup1,
1525                                                 SMESH::SMESH_GroupBase_ptr theGroup2,
1526                                                 const char*                theName )
1527 {
1528   SMESH::SMESH_Group_var aResGrp;
1529
1530   SMESH_TRY;
1531
1532   if ( _preMeshInfo )
1533     _preMeshInfo->FullLoadFromFile();
1534
1535   if ( theGroup1->_is_nil() || theGroup2->_is_nil() )
1536     THROW_SALOME_CORBA_EXCEPTION("CutGroups(): NULL Group",
1537                                  SALOME::BAD_PARAM);
1538   if ( theGroup1->GetType() != theGroup2->GetType() )
1539     THROW_SALOME_CORBA_EXCEPTION("CutGroups(): different group types",
1540                                  SALOME::BAD_PARAM);
1541   TPythonDump pyDump;
1542
1543   aResGrp = CreateGroup( theGroup1->GetType(), theName );
1544   if ( aResGrp->_is_nil() )
1545     return aResGrp._retn();
1546
1547   SMESHDS_GroupBase* groupDS1 = 0;
1548   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup1 ))
1549     groupDS1 = grp_i->GetGroupDS();
1550
1551   SMESHDS_GroupBase* groupDS2 = 0;
1552   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup2 ))
1553     groupDS2 = grp_i->GetGroupDS();
1554
1555   SMESHDS_Group* resGroupDS = 0;
1556   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aResGrp ))
1557     resGroupDS = dynamic_cast<SMESHDS_Group*>( grp_i->GetGroupDS() );
1558
1559   if ( groupDS1 && groupDS2 && resGroupDS )
1560   {
1561     SMDS_ElemIteratorPtr elemIt1 = groupDS1->GetElements();
1562     while ( elemIt1->more() )
1563     {
1564       const SMDS_MeshElement* e = elemIt1->next();
1565       if ( !groupDS2->Contains( e ))
1566         resGroupDS->SMDSGroup().Add( e );
1567     }
1568   }
1569   // Update Python script
1570   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var(_this()) << ".CutGroups( "
1571          << theGroup1 << ", " << theGroup2 << ", '" << theName << "')";
1572
1573   SMESH_CATCH( SMESH::throwCorbaException );
1574
1575   return aResGrp._retn();
1576 }
1577
1578 //=============================================================================
1579 /*!
1580   \brief Cut lists of groups. New group is created. All mesh elements that are
1581   present in main groups but do not present in tool groups are added to the new one
1582   \param theMainGroups list of main groups
1583   \param theToolGroups list of tool groups
1584   \param theName name of group to be created
1585   \return pointer on the group
1586 */
1587 //=============================================================================
1588
1589 SMESH::SMESH_Group_ptr
1590 SMESH_Mesh_i::CutListOfGroups(const SMESH::ListOfGroups& theMainGroups,
1591                               const SMESH::ListOfGroups& theToolGroups,
1592                               const char*                theName )
1593 {
1594   SMESH::SMESH_Group_var aResGrp;
1595
1596   SMESH_TRY;
1597
1598   if ( _preMeshInfo )
1599     _preMeshInfo->FullLoadFromFile();
1600
1601   if ( !theName )
1602     return SMESH::SMESH_Group::_nil();
1603
1604   // check types and get SMESHDS_GroupBase's
1605   SMESH::ElementType aType = SMESH::ALL;
1606   vector< SMESHDS_GroupBase* >   toolGroupVec;
1607   vector< SMDS_ElemIteratorPtr > mainIterVec;
1608
1609   for ( int g = 0, n = theMainGroups.length(); g < n; g++ )
1610   {
1611     SMESH::SMESH_GroupBase_var aGrp = theMainGroups[ g ];
1612     if ( CORBA::is_nil( aGrp ) )
1613       continue;
1614     if ( aType == SMESH::ALL )
1615       aType = aGrp->GetType();
1616     else if ( aType != aGrp->GetType() )
1617       THROW_SALOME_CORBA_EXCEPTION("CutListOfGroups(): different group types",
1618                                    SALOME::BAD_PARAM);
1619     if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aGrp ))
1620       if ( SMESHDS_GroupBase* grpDS = grp_i->GetGroupDS() )
1621         if ( !grpDS->IsEmpty() )
1622           mainIterVec.push_back( grpDS->GetElements() );
1623   }
1624   if ( aType == SMESH::ALL ) // all main groups are nil
1625     return SMESH::SMESH_Group::_nil();
1626   if ( mainIterVec.empty() ) // all main groups are empty
1627     return aResGrp._retn();
1628
1629   for ( int g = 0, n = theToolGroups.length(); g < n; g++ )
1630   {
1631     SMESH::SMESH_GroupBase_var aGrp = theToolGroups[ g ];
1632     if ( CORBA::is_nil( aGrp ) )
1633       continue;
1634     if ( aType != aGrp->GetType() )
1635       THROW_SALOME_CORBA_EXCEPTION("CutListOfGroups(): different group types",
1636                                    SALOME::BAD_PARAM);
1637     if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aGrp ))
1638       if ( SMESHDS_GroupBase* grpDS = grp_i->GetGroupDS() )
1639         toolGroupVec.push_back( grpDS );
1640   }
1641
1642   TPythonDump pyDump;
1643
1644   // Create a group
1645   aResGrp = CreateGroup( aType, theName );
1646
1647   SMESHDS_Group* resGroupDS = 0;
1648   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aResGrp ))
1649     resGroupDS = dynamic_cast<SMESHDS_Group*>( grp_i->GetGroupDS() );
1650   if ( !resGroupDS )
1651     return aResGrp._retn();
1652
1653   // Fill the group
1654   size_t i, nb = toolGroupVec.size();
1655   SMDS_ElemIteratorPtr mainElemIt
1656     ( new SMDS_IteratorOnIterators
1657       < const SMDS_MeshElement*, vector< SMDS_ElemIteratorPtr > >( mainIterVec ));
1658   while ( mainElemIt->more() )
1659   {
1660     const SMDS_MeshElement* e = mainElemIt->next();
1661     bool isIn = false;
1662     for ( i = 0; ( i < nb && !isIn ); ++i )
1663       isIn = toolGroupVec[i]->Contains( e );
1664
1665     if ( !isIn )
1666       resGroupDS->SMDSGroup().Add( e );
1667   }
1668
1669   // Update Python script
1670   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var( _this() )
1671          << ".CutListOfGroups( " << theMainGroups << ", "
1672          << theToolGroups << ", '" << theName << "' )";
1673
1674   SMESH_CATCH( SMESH::throwCorbaException );
1675
1676   return aResGrp._retn();
1677 }
1678
1679 namespace // functions making checks according to SMESH::NB_COMMON_NODES_ENUM
1680 {
1681   bool isAllNodesCommon(int nbChecked, int nbCommon, int nbNodes, int /*nbCorners*/,
1682                         bool & toStopChecking )
1683   {
1684     toStopChecking = ( nbCommon < nbChecked );
1685     return nbCommon == nbNodes;
1686   }
1687   bool isMainNodesCommon(int nbChecked, int nbCommon, int /*nbNodes*/, int nbCorners,
1688                          bool & toStopChecking )
1689   {
1690     toStopChecking = ( nbCommon < nbChecked || nbChecked >= nbCorners );
1691     return nbCommon == nbCorners;
1692   }
1693   bool isAtLeastOneNodeCommon(int /*nbChecked*/, int nbCommon, int /*nbNodes*/, int /*nbCorners*/,
1694                               bool & /*toStopChecking*/ )
1695   {
1696     return nbCommon > 0;
1697   }
1698   bool isMajorityOfNodesCommon(int /*nbChecked*/, int nbCommon, int nbNodes, int /*nbCorners*/,
1699                                bool & /*toStopChecking*/ )
1700   {
1701     return nbCommon >= (nbNodes+1) / 2;
1702   }
1703 }
1704
1705 //=============================================================================
1706 /*!
1707  * Create a group of entities basing on nodes of other groups.
1708  *  \param [in] theGroups - list of either groups, sub-meshes or filters.
1709  *  \param [in] anElemType - a type of elements to include to the new group.
1710  *  \param [in] theName - a name of the new group.
1711  *  \param [in] theNbCommonNodes - criterion of inclusion of an element to the new group.
1712  *  \param [in] theUnderlyingOnly - if \c True, an element is included to the
1713  *         new group provided that it is based on nodes of an element of \a aListOfGroups
1714  *  \return SMESH_Group - the created group
1715 */
1716 // IMP 19939, bug 22010, IMP 22635
1717 //=============================================================================
1718
1719 SMESH::SMESH_Group_ptr
1720 SMESH_Mesh_i::CreateDimGroup(const SMESH::ListOfIDSources& theGroups,
1721                              SMESH::ElementType            theElemType,
1722                              const char*                   theName,
1723                              SMESH::NB_COMMON_NODES_ENUM   theNbCommonNodes,
1724                              CORBA::Boolean                theUnderlyingOnly)
1725 {
1726   SMESH::SMESH_Group_var aResGrp;
1727
1728   SMESH_TRY;
1729   if ( _preMeshInfo )
1730     _preMeshInfo->FullLoadFromFile();
1731
1732   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
1733
1734   if ( !theName || !aMeshDS )
1735     return SMESH::SMESH_Group::_nil();
1736
1737   SMDSAbs_ElementType anElemType = (SMDSAbs_ElementType)theElemType;
1738
1739   bool (*isToInclude)(int nbChecked, int nbCommon, int nbNodes, int nbCorners, bool & toStop);
1740   SMESH_Comment nbCoNoStr( "SMESH.");
1741   switch ( theNbCommonNodes ) {
1742   case SMESH::ALL_NODES   : isToInclude = isAllNodesCommon;        nbCoNoStr<<"ALL_NODES"   ;break;
1743   case SMESH::MAIN        : isToInclude = isMainNodesCommon;       nbCoNoStr<<"MAIN"        ;break;
1744   case SMESH::AT_LEAST_ONE: isToInclude = isAtLeastOneNodeCommon;  nbCoNoStr<<"AT_LEAST_ONE";break;
1745   case SMESH::MAJORITY    : isToInclude = isMajorityOfNodesCommon; nbCoNoStr<<"MAJORITY"    ;break;
1746   default: return aResGrp._retn();
1747   }
1748   int nbChecked, nbCommon, nbNodes, nbCorners;
1749
1750   // Create a group
1751
1752   TPythonDump pyDump;
1753
1754   aResGrp = CreateGroup( theElemType, theName );
1755   if ( aResGrp->_is_nil() )
1756     return SMESH::SMESH_Group::_nil();
1757
1758   SMESHDS_GroupBase* groupBaseDS =
1759     SMESH::DownCast<SMESH_GroupBase_i*>( aResGrp )->GetGroupDS();
1760   SMDS_MeshGroup& resGroupCore = static_cast< SMESHDS_Group* >( groupBaseDS )->SMDSGroup();
1761
1762   vector<bool> isNodeInGroups;
1763
1764   for ( int g = 0, n = theGroups.length(); g < n; g++ ) // loop on theGroups
1765   {
1766     SMESH::SMESH_IDSource_var aGrp = theGroups[ g ];
1767     if ( CORBA::is_nil( aGrp ) )
1768       continue;
1769     SMESH::SMESH_Mesh_var mesh = aGrp->GetMesh();
1770     if ( mesh->_is_nil() || mesh->GetId() != this->GetId() )
1771       continue;
1772
1773     SMDS_ElemIteratorPtr elIt = GetElements( aGrp, SMESH::ALL );
1774     if ( !elIt ) continue;
1775
1776     if ( theElemType == SMESH::NODE ) // get all nodes of elements
1777     {
1778       while ( elIt->more() ) {
1779         const SMDS_MeshElement* el = elIt->next();
1780         SMDS_ElemIteratorPtr nIt = el->nodesIterator();
1781         while ( nIt->more() )
1782           resGroupCore.Add( nIt->next() );
1783       }
1784     }
1785     // get elements of theElemType based on nodes of every element of group
1786     else if ( theUnderlyingOnly )
1787     {
1788       while ( elIt->more() )
1789       {
1790         const SMDS_MeshElement* el = elIt->next(); // an element of ref group
1791         TIDSortedElemSet elNodes( el->begin_nodes(), el->end_nodes() );
1792         TIDSortedElemSet checkedElems;
1793         SMDS_NodeIteratorPtr nIt = el->nodeIterator();
1794         while ( nIt->more() )
1795         {
1796           const SMDS_MeshNode* n = nIt->next();
1797           SMDS_ElemIteratorPtr elOfTypeIt = n->GetInverseElementIterator( anElemType );
1798           // check nodes of elements of theElemType around el
1799           while ( elOfTypeIt->more() )
1800           {
1801             const SMDS_MeshElement* elOfType = elOfTypeIt->next();
1802             if ( !checkedElems.insert( elOfType ).second ) continue;
1803             nbNodes   = elOfType->NbNodes();
1804             nbCorners = elOfType->NbCornerNodes();
1805             nbCommon  = 0;
1806             bool toStopChecking = false;
1807             SMDS_ElemIteratorPtr nIt2 = elOfType->nodesIterator();
1808             for ( nbChecked = 1; nIt2->more() && !toStopChecking; ++nbChecked )
1809               if ( elNodes.count( nIt2->next() ) &&
1810                    isToInclude( nbChecked, ++nbCommon, nbNodes, nbCorners, toStopChecking ))
1811               {
1812                 resGroupCore.Add( elOfType );
1813                 break;
1814               }
1815           }
1816         }
1817       }
1818     }
1819     // get all nodes of elements of groups
1820     else
1821     {
1822       while ( elIt->more() )
1823       {
1824         const SMDS_MeshElement* el = elIt->next(); // an element of group
1825         SMDS_NodeIteratorPtr nIt = el->nodeIterator();
1826         while ( nIt->more() )
1827         {
1828           const SMDS_MeshNode* n = nIt->next();
1829           if ( n->GetID() >= (int) isNodeInGroups.size() )
1830             isNodeInGroups.resize( n->GetID() + 1, false );
1831           isNodeInGroups[ n->GetID() ] = true;
1832         }
1833       }
1834     }
1835   }
1836
1837   // Get elements of theElemType based on a certain number of nodes of elements of groups
1838   if ( !theUnderlyingOnly && !isNodeInGroups.empty() )
1839   {
1840     const SMDS_MeshNode* n;
1841     vector<bool> isElemChecked( aMeshDS->MaxElementID() + 1 );
1842     const int isNodeInGroupsSize = isNodeInGroups.size();
1843     for ( int iN = 0; iN < isNodeInGroupsSize; ++iN )
1844     {
1845       if ( !isNodeInGroups[ iN ] ||
1846            !( n = aMeshDS->FindNode( iN )))
1847         continue;
1848
1849       // check nodes of elements of theElemType around n
1850       SMDS_ElemIteratorPtr elOfTypeIt = n->GetInverseElementIterator( anElemType );
1851       while ( elOfTypeIt->more() )
1852       {
1853         const SMDS_MeshElement*  elOfType = elOfTypeIt->next();
1854         vector<bool>::reference isChecked = isElemChecked[ elOfType->GetID() ];
1855         if ( isChecked )
1856           continue;
1857         isChecked = true;
1858
1859         nbNodes   = elOfType->NbNodes();
1860         nbCorners = elOfType->NbCornerNodes();
1861         nbCommon  = 0;
1862         bool toStopChecking = false;
1863         SMDS_ElemIteratorPtr nIt = elOfType->nodesIterator();
1864         for ( nbChecked = 1; nIt->more() && !toStopChecking; ++nbChecked )
1865         {
1866           const smIdType nID = nIt->next()->GetID();
1867           if ( nID < isNodeInGroupsSize && isNodeInGroups[ nID ] &&
1868                isToInclude( nbChecked, ++nbCommon, nbNodes, nbCorners, toStopChecking ))
1869           {
1870             resGroupCore.Add( elOfType );
1871             break;
1872           }
1873         }
1874       }
1875     }
1876   }
1877
1878   // Update Python script
1879   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var( _this())
1880          << ".CreateDimGroup( "
1881          << theGroups << ", " << theElemType << ", '" << theName << "', "
1882          << nbCoNoStr << ", " << theUnderlyingOnly << ")";
1883
1884   SMESH_CATCH( SMESH::throwCorbaException );
1885
1886   return aResGrp._retn();
1887 }
1888
1889 //================================================================================
1890 /*!
1891  * \brief Distribute all faces of the mesh between groups using sharp edges and optionally
1892  *        existing 1D elements as group boundaries.
1893  *  \param [in] theSharpAngle - edge is considered sharp if an angle between normals of
1894  *              adjacent faces is more than \a sharpAngle in degrees.
1895  *  \param [in] theCreateEdges - to create 1D elements for detected sharp edges.
1896  *  \param [in] theUseExistingEdges - to use existing edges as group boundaries
1897  *  \return ListOfGroups - the created groups
1898  */
1899 //================================================================================
1900
1901 SMESH::ListOfGroups*
1902 SMESH_Mesh_i::FaceGroupsSeparatedByEdges( CORBA::Double  theSharpAngle,
1903                                           CORBA::Boolean theCreateEdges,
1904                                           CORBA::Boolean theUseExistingEdges )
1905 {
1906   if ( theSharpAngle < 0 || theSharpAngle > 180 )
1907     THROW_SALOME_CORBA_EXCEPTION("Invalid sharp angle, it must be between 0 and 180 degrees",
1908                                  SALOME::BAD_PARAM);
1909
1910   SMESH::ListOfGroups_var resultGroups = new SMESH::ListOfGroups;
1911
1912   TPythonDump pyDump;
1913
1914   SMESH_TRY;
1915   if ( _preMeshInfo )
1916     _preMeshInfo->FullLoadFromFile();
1917
1918   SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
1919
1920   std::vector< SMESH_MeshAlgos::Edge > edges =
1921     SMESH_MeshAlgos::FindSharpEdges( meshDS, theSharpAngle, theUseExistingEdges );
1922
1923   if ( theCreateEdges )
1924   {
1925     std::vector<const SMDS_MeshNode *> nodes(2);
1926     for ( size_t i = 0; i < edges.size(); ++i )
1927     {
1928       nodes[0] = edges[i]._node1;
1929       nodes[1] = edges[i]._node2;
1930       if ( meshDS->FindElement( nodes, SMDSAbs_Edge ))
1931         continue;
1932       if ( edges[i]._medium )
1933         meshDS->AddEdge( edges[i]._node1, edges[i]._node2, edges[i]._medium );
1934       else
1935         meshDS->AddEdge( edges[i]._node1, edges[i]._node2 );
1936     }
1937   }
1938
1939   std::vector< std::vector< const SMDS_MeshElement* > > faceGroups =
1940     SMESH_MeshAlgos::SeparateFacesByEdges( meshDS, edges );
1941
1942   SMESH::SMESH_MeshEditor_var editor = GetMeshEditor(); // create _editor
1943
1944   resultGroups->length( faceGroups.size() );
1945   for ( size_t iG = 0; iG < faceGroups.size(); ++iG )
1946   {
1947     SMESH::SMESH_Group_var group = CreateGroup( SMESH::FACE,
1948                                                 _editor->GenerateGroupName("Group").c_str());
1949     resultGroups[iG] = SMESH::SMESH_Group::_duplicate( group );
1950
1951     SMESHDS_GroupBase* groupBaseDS =
1952       SMESH::DownCast<SMESH_GroupBase_i*>( group )->GetGroupDS();
1953     SMDS_MeshGroup& groupCore = static_cast< SMESHDS_Group* >( groupBaseDS )->SMDSGroup();
1954
1955     std::vector< const SMDS_MeshElement* >& faces = faceGroups[ iG ];
1956     for ( size_t i = 0; i < faces.size(); ++i )
1957       groupCore.Add( faces[i] );
1958   }
1959
1960   pyDump << resultGroups << " = " << SMESH::SMESH_Mesh_var(_this())
1961          << ".FaceGroupsSeparatedByEdges( "
1962          << TVar( theSharpAngle ) << ", "
1963          << theCreateEdges << ", "
1964          << theUseExistingEdges << " )";
1965
1966   SMESH_CATCH( SMESH::throwCorbaException );
1967   return resultGroups._retn();
1968
1969 }
1970
1971 //================================================================================
1972 /*!
1973  * \brief Remember GEOM group data
1974  */
1975 //================================================================================
1976
1977 void SMESH_Mesh_i::addGeomGroupData(GEOM::GEOM_Object_ptr theGeomObj,
1978                                     CORBA::Object_ptr     theSmeshObj)
1979 {
1980   if ( CORBA::is_nil( theGeomObj ) || theGeomObj->GetType() != GEOM_GROUP )
1981     return;
1982   // group SO
1983   SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( theGeomObj );
1984   if ( groupSO->_is_nil() )
1985     return;
1986   // group indices
1987   GEOM::GEOM_Gen_var               geomGen = _gen_i->GetGeomEngine( theGeomObj );
1988   GEOM::GEOM_IGroupOperations_wrap groupOp = geomGen->GetIGroupOperations();
1989   GEOM::ListOfLong_var                 ids = groupOp->GetObjects( theGeomObj );
1990
1991   // store data
1992   _geomGroupData.push_back( TGeomGroupData() );
1993   TGeomGroupData & groupData = _geomGroupData.back();
1994   // entry
1995   CORBA::String_var entry = groupSO->GetID();
1996   groupData._groupEntry = entry.in();
1997   // indices
1998   for ( CORBA::ULong i = 0; i < ids->length(); ++i )
1999     groupData._indices.insert( ids[i] );
2000   // SMESH object
2001   groupData._smeshObject = CORBA::Object::_duplicate( theSmeshObj );
2002   // shape index in SMESHDS
2003   // TopoDS_Shape shape = _gen_i->GeomObjectToShape( theGeomObj );
2004   // groupData._dsID = shape.IsNull() ? 0 : _impl->GetSubMesh( shape )->GetId();
2005 }
2006
2007 //================================================================================
2008 /*!
2009  * Remove GEOM group data relating to removed smesh object
2010  */
2011 //================================================================================
2012
2013 void SMESH_Mesh_i::removeGeomGroupData(CORBA::Object_ptr theSmeshObj)
2014 {
2015   list<TGeomGroupData>::iterator
2016     data = _geomGroupData.begin(), dataEnd = _geomGroupData.end();
2017   for ( ; data != dataEnd; ++data ) {
2018     if ( theSmeshObj->_is_equivalent( data->_smeshObject )) {
2019       _geomGroupData.erase( data );
2020       return;
2021     }
2022   }
2023 }
2024
2025 //================================================================================
2026 /*!
2027 * \brief Replace a shape in the mesh upon Break Link
2028 */
2029 //================================================================================
2030
2031 void SMESH_Mesh_i::ReplaceShape(GEOM::GEOM_Object_ptr theNewGeom)
2032 {
2033   // check if geometry changed
2034   bool geomChanged = true;
2035   GEOM::GEOM_Object_var oldGeom = GetShapeToMesh();
2036   if ( !theNewGeom->_is_nil() && !oldGeom->_is_nil() )
2037     geomChanged = ( oldGeom->GetTick() != theNewGeom->GetTick() );
2038
2039   TopoDS_Shape S = _impl->GetShapeToMesh();
2040   GEOM_Client* geomClient = _gen_i->GetShapeReader();
2041   TCollection_AsciiString aIOR;
2042   if ( geomClient->Find( S, aIOR ))
2043     geomClient->RemoveShapeFromBuffer( aIOR );
2044
2045   // clear buffer also for sub-groups
2046   SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
2047   const std::set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
2048   std::set<SMESHDS_GroupBase*>::const_iterator g = groups.begin();
2049   for (; g != groups.end(); ++g)
2050     if (const SMESHDS_GroupOnGeom* group = dynamic_cast<SMESHDS_GroupOnGeom*>(*g))
2051     {
2052       const TopoDS_Shape& s = group->GetShape();
2053       if ( geomClient->Find( s, aIOR ))
2054         geomClient->RemoveShapeFromBuffer( aIOR );
2055     }
2056
2057   // clear buffer also for sub-meshes
2058   std::map<int, SMESH_subMesh_i*>::const_iterator aSubMeshIter = _mapSubMesh_i.cbegin();
2059   for(; aSubMeshIter != _mapSubMesh_i.cend(); aSubMeshIter++) {
2060     int aShapeID = aSubMeshIter->first;
2061     const TopoDS_Shape& aSubShape = meshDS->IndexToShape(aShapeID);
2062     TCollection_AsciiString aShapeIOR;
2063     if ( geomClient->Find( aSubShape, aShapeIOR ))
2064       geomClient->RemoveShapeFromBuffer( aShapeIOR );
2065   }
2066
2067   typedef struct {
2068     int shapeID; smIdType fromID, toID; // indices of elements of a sub-mesh
2069   } TRange;
2070   std::vector< TRange > elemRanges, nodeRanges; // elements of sub-meshes
2071   std::vector< SMDS_PositionPtr > positions; // node positions
2072   if ( !geomChanged )
2073   {
2074     // store positions of elements on geometry
2075     Load();
2076     if ( meshDS->MaxNodeID()    > meshDS->NbNodes() ||
2077          meshDS->MaxElementID() > meshDS->NbElements() )
2078     {
2079       meshDS->Modified();
2080       meshDS->CompactMesh();
2081     }
2082     positions.resize( meshDS->NbNodes() + 1 );
2083     for ( SMDS_NodeIteratorPtr nodeIt = meshDS->nodesIterator(); nodeIt->more(); )
2084     {
2085       const SMDS_MeshNode* n = nodeIt->next();
2086       positions[ n->GetID() ] = n->GetPosition();
2087     }
2088
2089     // remove elements from sub-meshes to avoid their removal at hypotheses addition
2090     for ( int isNode = 0; isNode < 2; ++isNode )
2091     {
2092       std::vector< TRange > & ranges = isNode ? nodeRanges : elemRanges;
2093       ranges.reserve( meshDS->MaxShapeIndex() + 10 );
2094       ranges.push_back( TRange{ 0,0,0 });
2095       SMDS_ElemIteratorPtr elemIt = meshDS->elementsIterator( isNode ? SMDSAbs_Node : SMDSAbs_All );
2096       while ( elemIt->more() )
2097       {
2098         const SMDS_MeshElement* e = elemIt->next();
2099         const smIdType     elemID = e->GetID();
2100         const int         shapeID = e->GetShapeID();
2101         TRange &        lastRange = ranges.back();
2102         if ( lastRange.shapeID != shapeID ||
2103              lastRange.toID    != elemID )
2104           ranges.push_back( TRange{ shapeID, elemID, elemID + 1 });
2105         else
2106           lastRange.toID = elemID + 1;
2107
2108         if ( SMESHDS_SubMesh* sm = meshDS->MeshElements( shapeID ))
2109         {
2110           if ( isNode ) sm->RemoveNode( static_cast< const SMDS_MeshNode *>( e ));
2111           else          sm->RemoveElement( e );
2112         }
2113       }
2114     }
2115   }
2116
2117
2118   // update the reference to theNewGeom (needed for correct execution of a dumped python script)
2119   SMESH::SMESH_Mesh_var   me = _this();
2120   SALOMEDS::SObject_wrap aSO = _gen_i->ObjectToSObject( me );
2121   CORBA::String_var    entry = theNewGeom->GetStudyEntry();
2122   if ( !aSO->_is_nil() )
2123   {
2124     SALOMEDS::SObject_wrap aShapeRefSO;
2125     if ( aSO->FindSubObject( _gen_i->GetRefOnShapeTag(), aShapeRefSO.inout() ))
2126     {
2127       SALOMEDS::SObject_wrap    aShapeSO = _gen_i->getStudyServant()->FindObjectID( entry );
2128       SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
2129       builder->Addreference( aShapeRefSO, aShapeSO );
2130     }
2131   }
2132
2133   // re-assign global hypotheses to the new shape
2134   _mainShapeTick = geomChanged ? -1 : theNewGeom->GetTick();
2135   CheckGeomModif( true );
2136
2137   if ( !geomChanged )
2138   {
2139     // restore positions of elements on geometry
2140     for ( int isNode = 0; isNode < 2; ++isNode )
2141     {
2142       std::vector< TRange > & ranges = isNode ? nodeRanges : elemRanges;
2143       for ( size_t i = 1; i < ranges.size(); ++i )
2144       {
2145         int elemID = ranges[ i ].fromID;
2146         int   toID = ranges[ i ].toID;
2147         SMESHDS_SubMesh * smDS = meshDS->NewSubMesh( ranges[ i ].shapeID );
2148         if ( isNode )
2149           for ( ; elemID < toID; ++elemID )
2150             smDS->AddNode( meshDS->FindNode( elemID ));
2151         else
2152           for ( ; elemID < toID; ++elemID )
2153             smDS->AddElement( meshDS->FindElement( elemID ));
2154
2155         if ( SMESH_subMesh* sm = _impl->GetSubMeshContaining( ranges[ i ].shapeID ))
2156           sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
2157       }
2158     }
2159     for ( unsigned int nodeID = 1; nodeID < positions.size(); ++nodeID )
2160       if ( positions[ nodeID ])
2161         if ( SMDS_MeshNode* n = const_cast< SMDS_MeshNode*>( meshDS->FindNode( nodeID )))
2162           n->SetPosition( positions[ nodeID ], n->GetShapeID() );
2163
2164     // restore icons
2165     _gen_i->UpdateIcons( SMESH::SMESH_Mesh_var( _this() ));
2166   }
2167
2168   TPythonDump() << "SHAPERSTUDY.breakLinkForSubElements(salome.ObjectToSObject("
2169                 << me <<".GetMesh()), " << entry.in() << ")";
2170
2171   TPythonDump() <<  me << ".ReplaceShape( " << entry.in() << " )";
2172
2173 }
2174
2175 //================================================================================
2176 /*!
2177  * \brief Return new group contents if it has been changed and update group data
2178  */
2179 //================================================================================
2180
2181 enum { ONLY_IF_CHANGED, IS_BREAK_LINK, MAIN_TRANSFORMED };
2182
2183 TopoDS_Shape SMESH_Mesh_i::newGroupShape( TGeomGroupData & groupData, int how )
2184 {
2185   TopoDS_Shape newShape;
2186   SALOMEDS::SObject_wrap groupSO;
2187
2188   if ( how == IS_BREAK_LINK )
2189   {
2190     SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( groupData._smeshObject );
2191     SALOMEDS::SObject_wrap geomRefSO;
2192     if ( !meshSO->_is_nil() &&
2193          meshSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ))
2194     {
2195       geomRefSO->ReferencedObject( groupSO.inout() );
2196     }
2197   }
2198   else
2199   {
2200     // get geom group
2201     groupSO = _gen_i->getStudyServant()->FindObjectID( groupData._groupEntry.c_str() );
2202   }
2203
2204   if ( groupSO->_is_nil() )
2205     return newShape;
2206
2207   CORBA::Object_var      groupObj = _gen_i->SObjectToObject( groupSO );
2208   GEOM::GEOM_Object_var geomGroup = GEOM::GEOM_Object::_narrow( groupObj );
2209   if ( geomGroup->_is_nil() )
2210     return newShape;
2211
2212   // get indices of group items
2213   set<int> curIndices;
2214   GEOM::GEOM_Gen_var               geomGen = _gen_i->GetGeomEngine( geomGroup );
2215   GEOM::GEOM_IGroupOperations_wrap groupOp = geomGen->GetIGroupOperations();
2216   GEOM::ListOfLong_var                 ids = groupOp->GetObjects( geomGroup );
2217   for ( CORBA::ULong i = 0; i < ids->length(); ++i )
2218     curIndices.insert( ids[i] );
2219
2220   bool sameIndices = ( groupData._indices == curIndices );
2221   if ( how == ONLY_IF_CHANGED && sameIndices )
2222     return newShape; // group not changed
2223
2224   // update data
2225   CORBA::String_var entry = geomGroup->GetStudyEntry();
2226   groupData._groupEntry = entry.in();
2227   groupData._indices = curIndices;
2228
2229   newShape = _gen_i->GeomObjectToShape( geomGroup );
2230
2231   // check if newShape is up-to-date
2232   if ( !newShape.IsNull() && ids->length() > 0 )
2233   {
2234     bool toUpdate = ! _impl->GetMeshDS()->IsGroupOfSubShapes( newShape );
2235     if ( !toUpdate )
2236     {
2237       TopExp_Explorer exp( newShape, (TopAbs_ShapeEnum)( groupOp->GetType( geomGroup )));
2238       for ( ; exp.More() && !toUpdate; exp.Next() )
2239       {
2240         int ind = _impl->GetMeshDS()->ShapeToIndex( exp.Current() );
2241         toUpdate = ( curIndices.erase( ind ) == 0 );
2242       }
2243       if ( !curIndices.empty() )
2244         toUpdate = true;
2245     }
2246     if ( toUpdate )
2247     {
2248       GEOM_Client*    geomClient = _gen_i->GetShapeReader();
2249       CORBA::String_var groupIOR = geomGen->GetStringFromIOR( geomGroup );
2250       geomClient->RemoveShapeFromBuffer( groupIOR.in() );
2251       newShape = _gen_i->GeomObjectToShape( geomGroup );
2252     }
2253   }
2254   else
2255   {
2256     // geom group becomes empty - return empty compound
2257     TopoDS_Compound compound;
2258     BRep_Builder().MakeCompound(compound);
2259     newShape = compound;
2260   }
2261
2262   return newShape;
2263 }
2264
2265 namespace
2266 {
2267   //-----------------------------------------------------------------------------
2268   /*!
2269    * \brief Storage of shape and index used in CheckGeomGroupModif()
2270    */
2271   struct TIndexedShape
2272   {
2273     int          _index;
2274     TopoDS_Shape _shape;
2275     TIndexedShape( int i, const TopoDS_Shape& s ):_index(i), _shape(s) {}
2276   };
2277   //-----------------------------------------------------------------------------
2278   /*!
2279    * \brief Data to re-create a group on geometry
2280    */
2281   struct TGroupOnGeomData
2282   {
2283     int                 _oldID;
2284     TopoDS_Shape        _shape;
2285     SMDSAbs_ElementType _type;
2286     std::string         _name;
2287     Quantity_Color      _color;
2288
2289     TGroupOnGeomData( const SMESHDS_GroupOnGeom* group )
2290     {
2291       _oldID = group->GetID();
2292       _type  = group->GetType();
2293       _name  = group->GetStoreName();
2294       _color = group->GetColor();
2295     }
2296   };
2297
2298   //-----------------------------------------------------------------------------
2299   /*!
2300    * \brief Check if a filter is still valid after geometry removal
2301    */
2302   bool isValidGeomFilter( SMESH::Filter_var theFilter )
2303   {
2304     if ( theFilter->_is_nil() )
2305       return false;
2306     SMESH::Filter::Criteria_var criteria;
2307     theFilter->GetCriteria( criteria.out() );
2308
2309     for ( CORBA::ULong iCr = 0; iCr < criteria->length(); ++iCr )
2310     {
2311       const char* thresholdID = criteria[ iCr ].ThresholdID.in();
2312       std::string entry;
2313       switch ( criteria[ iCr ].Type )
2314       {
2315       case SMESH::FT_BelongToGeom:
2316       case SMESH::FT_BelongToPlane:
2317       case SMESH::FT_BelongToCylinder:
2318       case SMESH::FT_BelongToGenSurface:
2319       case SMESH::FT_LyingOnGeom:
2320         entry = thresholdID;
2321         break;
2322       case SMESH::FT_ConnectedElements:
2323         if ( thresholdID )
2324         {
2325           entry = thresholdID;
2326           break;
2327         }
2328       default:
2329         continue;
2330       }
2331       SMESH_Gen_i*           gen = SMESH_Gen_i::GetSMESHGen();
2332       SALOMEDS::SObject_wrap  so = gen->getStudyServant()->FindObjectID( entry.c_str() );
2333       if ( so->_is_nil() )
2334         return false;
2335       CORBA::Object_var      obj = so->GetObject();
2336       GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( obj );
2337       if ( gen->GeomObjectToShape( geom ).IsNull() )
2338         return false;
2339
2340     } // loop on criteria
2341
2342     return true;
2343   }
2344 }
2345
2346 //=============================================================================
2347 /*!
2348  * \brief Update data if geometry changes
2349  *
2350  * Issue 0022501
2351  */
2352 //=============================================================================
2353
2354 void SMESH_Mesh_i::CheckGeomModif( bool theIsBreakLink )
2355 {
2356   SMESH::SMESH_Mesh_var me = _this();
2357   GEOM::GEOM_Object_var mainGO = GetShapeToMesh();
2358
2359   TPythonDump dumpNothing; // prevent any dump
2360
2361   //bool removedFromClient = false;
2362
2363   if ( mainGO->_is_nil() ) // GEOM_Client cleared or geometry removed? (IPAL52735, PAL23636)
2364   {
2365     //removedFromClient = _impl->HasShapeToMesh();
2366
2367     // try to find geometry by study reference
2368     SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( me );
2369     SALOMEDS::SObject_wrap geomRefSO, geomSO;
2370     if ( !meshSO->_is_nil() &&
2371          meshSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
2372          geomRefSO->ReferencedObject( geomSO.inout() ))
2373     {
2374       CORBA::Object_var geomObj = _gen_i->SObjectToObject( geomSO );
2375       mainGO = GEOM::GEOM_Object::_narrow( geomObj );
2376     }
2377
2378     if ( mainGO->_is_nil() &&    // geometry removed ==>
2379          !geomRefSO->_is_nil() ) // remove geom dependent data: sub-meshes etc.
2380     {
2381       // convert geom dependent groups into standalone ones
2382       CheckGeomGroupModif();
2383
2384       _impl->ShapeToMesh( TopoDS_Shape() );
2385
2386       // remove sub-meshes
2387       std::map<int, SMESH::SMESH_subMesh_ptr>::iterator i_sm = _mapSubMeshIor.begin();
2388       while ( i_sm != _mapSubMeshIor.end() )
2389       {
2390         SMESH::SMESH_subMesh_ptr sm = i_sm->second;
2391         ++i_sm;
2392         RemoveSubMesh( sm );
2393       }
2394       // remove all children except groups in the study
2395       SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
2396       SALOMEDS::SObject_wrap so;
2397       for ( CORBA::Long tag = SMESH::Tag_RefOnShape; tag <= SMESH::Tag_LastSubMesh; ++tag )
2398         if ( meshSO->FindSubObject( tag, so.inout() ))
2399           builder->RemoveObjectWithChildren( so );
2400
2401       _gen_i->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED" );
2402
2403       return;
2404     }
2405   }
2406
2407   if ( !_impl->HasShapeToMesh() ) return;
2408
2409
2410   // Update after group modification
2411
2412   const bool geomChanged = ( mainGO->GetTick() != _mainShapeTick );
2413   if ( !theIsBreakLink )
2414     if ( mainGO->GetType() == GEOM_GROUP || !geomChanged )  // is group or not modified
2415     {
2416       smIdType nb = NbNodes() + NbElements();
2417       CheckGeomGroupModif();
2418       bool updated = ( nb != NbNodes() + NbElements() );
2419       if ( updated ) // something removed due to hypotheses change
2420         _gen_i->UpdateIcons( me );
2421       if ( updated == geomChanged || nb == 0 )
2422         return;
2423     }
2424
2425   // Update after shape modification or breakLink w/o geometry change
2426
2427   GEOM_Client* geomClient = _gen_i->GetShapeReader();
2428   if ( !geomClient ) return;
2429   GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine( mainGO );
2430   if ( geomGen->_is_nil() ) return;
2431   CORBA::String_var geomComponentType = geomGen->ComponentDataType();
2432   bool isShaper = ( strcmp( geomComponentType.in(), "SHAPERSTUDY" ) == 0 );
2433
2434   SMESHDS_Mesh * meshDS = _impl->GetMeshDS();
2435
2436   TopoDS_Shape newShape = _gen_i->GeomObjectToShape( mainGO );
2437   if ( meshDS->ShapeToIndex( newShape ) == 1 ) // not yet updated
2438   {
2439     CORBA::String_var ior = geomGen->GetStringFromIOR( mainGO );
2440     geomClient->RemoveShapeFromBuffer( ior.in() );
2441     newShape = _gen_i->GeomObjectToShape( mainGO );
2442   }
2443
2444   // Update data taking into account that if topology doesn't change
2445   // all sub-shapes change but IDs of sub-shapes remain (except for geom groups)
2446
2447   if ( _preMeshInfo )
2448     _preMeshInfo->ForgetAllData();
2449
2450   if ( geomChanged || !isShaper )
2451     _impl->Clear();
2452   if ( newShape.IsNull() )
2453     return;
2454
2455   _mainShapeTick = mainGO->GetTick();
2456
2457   // store data of groups on geometry including new TopoDS_Shape's
2458   std::vector< TGroupOnGeomData > groupsData;
2459   const std::set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
2460   groupsData.reserve( groups.size() );
2461   TopTools_DataMapOfShapeShape old2newShapeMap;
2462   std::set<SMESHDS_GroupBase*>::const_iterator g = groups.begin();
2463   for ( ; g != groups.end(); ++g )
2464   {
2465     if ( const SMESHDS_GroupOnGeom* group = dynamic_cast< SMESHDS_GroupOnGeom* >( *g ))
2466     {
2467       groupsData.push_back( TGroupOnGeomData( group ));
2468
2469       // get a new shape
2470       SMESH::SMESH_GroupOnGeom_var gog;
2471       std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.find( group->GetID() );
2472       if ( i_grp != _mapGroups.end() )
2473         gog = SMESH::SMESH_GroupOnGeom::_narrow( i_grp->second );
2474
2475       GEOM::GEOM_Object_var geom;
2476       if ( !gog->_is_nil() )
2477       {
2478         if ( !theIsBreakLink )
2479           geom = gog->GetShape();
2480
2481         if ( theIsBreakLink || geom->_is_nil() )
2482         {
2483           SALOMEDS::SObject_wrap grpSO = _gen_i->ObjectToSObject( gog );
2484           SALOMEDS::SObject_wrap geomRefSO, geomSO;
2485           if ( !grpSO->_is_nil() &&
2486                grpSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
2487                geomRefSO->ReferencedObject( geomSO.inout() ))
2488           {
2489             CORBA::Object_var geomObj = _gen_i->SObjectToObject( geomSO );
2490             geom = GEOM::GEOM_Object::_narrow( geomObj );
2491           }
2492         }
2493       }
2494       if ( old2newShapeMap.IsBound( group->GetShape() ))
2495       {
2496         groupsData.back()._shape = old2newShapeMap( group->GetShape() );
2497       }
2498       else if ( !geom->_is_nil() )
2499       {
2500         groupsData.back()._shape = _gen_i->GeomObjectToShape( geom );
2501         if ( meshDS->IsGroupOfSubShapes( groupsData.back()._shape ))
2502         {
2503           CORBA::String_var ior = geomGen->GetStringFromIOR( geom );
2504           geomClient->RemoveShapeFromBuffer( ior.in() );
2505           groupsData.back()._shape = _gen_i->GeomObjectToShape( geom );
2506         }
2507         old2newShapeMap.Bind( group->GetShape(), groupsData.back()._shape );
2508       }
2509       
2510     }
2511   }
2512   // store assigned hypotheses
2513   std::vector< pair< int, THypList > > ids2Hyps;
2514   const ShapeToHypothesis & hyps = meshDS->GetHypotheses();
2515   for ( ShapeToHypothesis::Iterator s2hyps( hyps ); s2hyps.More(); s2hyps.Next() )
2516   {
2517     const TopoDS_Shape& s = s2hyps.Key();
2518     const THypList&  hyps = s2hyps.ChangeValue();
2519     ids2Hyps.push_back( make_pair( meshDS->ShapeToIndex( s ), hyps ));
2520   }
2521
2522   std::multimap< std::set<int>, int > ii2iMap; // group sub-ids to group id in SMESHDS
2523
2524   // count shapes excluding compounds corresponding to geom groups
2525   int oldNbSubShapes = meshDS->MaxShapeIndex();
2526   for ( ; oldNbSubShapes > 0; --oldNbSubShapes )
2527   {
2528     const TopoDS_Shape& s = meshDS->IndexToShape( oldNbSubShapes );
2529     if ( s.IsNull() || s.ShapeType() != TopAbs_COMPOUND )
2530       break;
2531     // fill ii2iMap
2532     std::set<int> subIds;
2533     for ( TopoDS_Iterator it( s ); it.More(); it.Next() )
2534       subIds.insert( meshDS->ShapeToIndex( it.Value() ));
2535     ii2iMap.insert( std::make_pair( subIds, oldNbSubShapes ));
2536   }
2537
2538   // check if shape topology changes - save shape type per shape ID
2539   std::vector< TopAbs_ShapeEnum > shapeTypes( Max( oldNbSubShapes + 1, 1 ));
2540   for ( int shapeID = oldNbSubShapes; shapeID > 0; --shapeID )
2541     shapeTypes[ shapeID ] = meshDS->IndexToShape( shapeID ).ShapeType();
2542
2543   // change shape to mesh
2544   _impl->ShapeToMesh( TopoDS_Shape() );
2545   _impl->ShapeToMesh( newShape );
2546
2547   // check if shape topology changes - check new shape types
2548   bool sameTopology = ( oldNbSubShapes == meshDS->MaxShapeIndex() );
2549   for ( int shapeID = oldNbSubShapes; shapeID > 0 &&  sameTopology; --shapeID )
2550   {
2551     const TopoDS_Shape& s = meshDS->IndexToShape( shapeID );
2552     sameTopology = ( !s.IsNull() && s.ShapeType() == shapeTypes[ shapeID ]);
2553   }
2554
2555   // re-add shapes (compounds) of geom groups
2556   typedef std::map< std::vector< int >, TGeomGroupData* > TIndices2GroupData;
2557   TIndices2GroupData ii2grData;
2558   std::vector< int > ii;
2559   std::map< int, int > old2newIDs; // group IDs
2560   std::list<TGeomGroupData>::iterator dataIt = _geomGroupData.begin();
2561   for ( ; dataIt != _geomGroupData.end(); ++dataIt )
2562   {
2563     TGeomGroupData* data = &(*dataIt);
2564     ii.reserve( data->_indices.size() );
2565     ii.assign( data->_indices.begin(), data->_indices.end() );
2566     TIndices2GroupData::iterator ii2gd = ii2grData.insert( std::make_pair( ii, data )).first;
2567     if ( ii2gd->second != data )
2568     {
2569       data->_groupEntry = ii2gd->second->_groupEntry;
2570       data->_indices    = ii2gd->second->_indices;
2571       continue;
2572     }
2573     const int  oldNbSub = data->_indices.size();
2574     const int soleOldID = oldNbSub == 1 ? *data->_indices.begin() : 0;
2575     int oldID = 0;
2576     std::multimap< std::set<int>, int >::iterator ii2i = ii2iMap.find( data->_indices );
2577     if ( ii2i != ii2iMap.end() )
2578     {
2579       oldID = ii2i->second;
2580       ii2iMap.erase( ii2i );
2581     }
2582     if ( !oldID && oldNbSub == 1 )
2583       oldID = soleOldID;
2584     if ( old2newIDs.count( oldID ))
2585       continue;
2586
2587     int how = ( theIsBreakLink || !sameTopology ) ? IS_BREAK_LINK : MAIN_TRANSFORMED;
2588     newShape = newGroupShape( *data, how );
2589
2590     if ( !newShape.IsNull() )
2591     {
2592       if ( oldNbSub > 1 && meshDS->ShapeToIndex( newShape ) > 0 ) // group reduced to one sub-shape
2593       {
2594         TopoDS_Compound compound;
2595         BRep_Builder().MakeCompound( compound );
2596         BRep_Builder().Add( compound, newShape );
2597         newShape = compound;
2598       }
2599       int newID = _impl->GetSubMesh( newShape )->GetId();
2600       if ( oldID /*&& oldID != newID*/ )
2601         old2newIDs.insert( std::make_pair( oldID, newID ));
2602       if ( oldNbSub == 1 )
2603         old2newIDs.insert( std::make_pair( soleOldID, newID ));
2604     }
2605   }
2606
2607   // re-assign hypotheses
2608   for ( size_t i = 0; i < ids2Hyps.size(); ++i )
2609   {
2610     int sID = ids2Hyps[i].first;
2611     if ( sID != 1 )
2612     {
2613       std::map< int, int >::iterator o2n = old2newIDs.find( sID );
2614       if ( o2n != old2newIDs.end() )
2615         sID = o2n->second;
2616       else if ( !sameTopology )
2617         continue;
2618     }
2619     const TopoDS_Shape& s = meshDS->IndexToShape( sID );
2620     if ( s.IsNull() )
2621       continue;
2622     const THypList& hyps = ids2Hyps[i].second;
2623     THypList::const_iterator h = hyps.begin();
2624     for ( ; h != hyps.end(); ++h )
2625       _impl->AddHypothesis( s, (*h)->GetID() );
2626   }
2627
2628   {
2629     // restore groups on geometry
2630     for ( size_t i = 0; i < groupsData.size(); ++i )
2631     {
2632       const TGroupOnGeomData& data = groupsData[i];
2633       if ( data._shape.IsNull() )
2634         continue;
2635
2636       std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i2g = _mapGroups.find( data._oldID );
2637       if ( i2g == _mapGroups.end() ) continue;
2638
2639       SMESH_GroupBase_i* gr_i = SMESH::DownCast<SMESH_GroupBase_i*>( i2g->second );
2640       if ( !gr_i ) continue;
2641
2642       SMESH_Group* g = _impl->AddGroup( data._type, data._name.c_str(), data._oldID, data._shape );
2643       if ( !g )
2644         _mapGroups.erase( i2g );
2645       else
2646         g->GetGroupDS()->SetColor( data._color );
2647     }
2648
2649     if ( !sameTopology )
2650     {
2651       std::map< int, int >::iterator o2n = old2newIDs.begin();
2652       for ( ; o2n != old2newIDs.end(); ++o2n )
2653       {
2654         int newID = o2n->second, oldID = o2n->first;
2655         if ( newID == oldID || !_mapSubMesh.count( oldID ))
2656           continue;
2657         if ( newID > 0 )
2658         {
2659           _mapSubMesh   [ newID ] = _impl->GetSubMeshContaining( newID );
2660           _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2661           _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2662         }
2663         _mapSubMesh.   erase(oldID);
2664         _mapSubMesh_i. erase(oldID);
2665         _mapSubMeshIor.erase(oldID);
2666         if ( newID > 0 )
2667           _mapSubMesh_i [ newID ]->changeLocalId( newID );
2668       }
2669     }
2670
2671     // update _mapSubMesh
2672     std::map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
2673     for ( ; i_sm != _mapSubMesh.end(); ++i_sm )
2674       i_sm->second = _impl->GetSubMesh( meshDS->IndexToShape( i_sm->first ));
2675   }
2676
2677   if ( !sameTopology )
2678   {
2679     // remove invalid study sub-objects
2680     CheckGeomGroupModif();
2681   }
2682
2683   _gen_i->UpdateIcons( me );
2684
2685   if ( !theIsBreakLink && isShaper )
2686   {
2687     SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( me );
2688     if ( !meshSO->_is_nil() )
2689       _gen_i->SetPixMap(meshSO, "ICON_SMESH_TREE_GEOM_MODIF");
2690   }
2691 }
2692
2693 //=============================================================================
2694 /*!
2695  * \brief Update objects depending on changed geom groups
2696  *
2697  * NPAL16168: geometrical group edition from a submesh don't modify mesh computation
2698  * issue 0020210: Update of a smesh group after modification of the associated geom group
2699  */
2700 //=============================================================================
2701
2702 void SMESH_Mesh_i::CheckGeomGroupModif()
2703 {
2704   // remove sub-meshes referring a removed sub-shapes (if main shape still exists)
2705   SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
2706   GEOM::GEOM_Object_var  mainGO = GetShapeToMesh();
2707   SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( SMESH::SMESH_Mesh_var( _this() ));
2708   if ( !mainGO->_is_nil() && !meshSO->_is_nil() )
2709   {
2710     SALOMEDS::SObject_wrap rootSO, geomRefSO, geomSO;
2711     for ( CORBA::Long tag = SMESH::Tag_FirstSubMesh; tag <= SMESH::Tag_LastSubMesh; ++tag )
2712       if ( meshSO->FindSubObject( tag, rootSO.inout() ))
2713       {
2714         int nbValid = 0, nbRemoved = 0;
2715         SALOMEDS::ChildIterator_wrap chItr = _gen_i->getStudyServant()->NewChildIterator( rootSO );
2716         for ( ; chItr->More(); chItr->Next() )
2717         {
2718           SALOMEDS::SObject_wrap smSO = chItr->Value(); // sub-mesh SO
2719           if ( !smSO->_is_nil() &&
2720                smSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
2721                geomRefSO->ReferencedObject( geomSO.inout() )) // find geometry by reference
2722           {
2723             CORBA::Object_var  geomObj = _gen_i->SObjectToObject( geomSO );
2724             GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( geomObj );
2725             if ( !geom->_non_existent() )
2726             {
2727               ++nbValid;
2728               continue; // keep the sub-mesh
2729             }
2730           }
2731           CORBA::Object_var     smObj = _gen_i->SObjectToObject( smSO );
2732           SMESH::SMESH_subMesh_var sm = SMESH::SMESH_subMesh::_narrow( smObj );
2733           if ( !sm->_is_nil() && !sm->_non_existent() )
2734           {
2735             GEOM::GEOM_Object_var smGeom = sm->GetSubShape();
2736             if ( smGeom->_is_nil() )
2737             {
2738               RemoveSubMesh( sm );
2739               ++nbRemoved;
2740             }
2741           }
2742           else
2743           {
2744             if ( _preMeshInfo )
2745               _preMeshInfo->ForgetAllData(); // unknown hypothesis modified
2746             builder->RemoveObjectWithChildren( smSO ); // sub-shape removed before loading SMESH
2747             ++nbRemoved;
2748           }
2749         }
2750         if ( /*nbRemoved > 0 &&*/ nbValid == 0 )
2751           builder->RemoveObjectWithChildren( rootSO );
2752       }
2753   }
2754
2755   // check for removed sub-shapes and convert geom dependent groups into standalone ones
2756   std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
2757   while ( i_gr != _mapGroups.end())
2758   {
2759     SMESH::SMESH_GroupBase_ptr group = i_gr->second;
2760     ++i_gr;
2761     SALOMEDS::SObject_wrap        groupSO = _gen_i->ObjectToSObject( group ), refSO, geomSO;
2762     SMESH::SMESH_GroupOnGeom_var   onGeom = SMESH::SMESH_GroupOnGeom::_narrow  ( group );
2763     SMESH::SMESH_GroupOnFilter_var onFilt = SMESH::SMESH_GroupOnFilter::_narrow( group );
2764     bool isValidGeom = false;
2765     if ( !onGeom->_is_nil() )
2766     {
2767       isValidGeom = ( ! GEOM::GEOM_Object_var( onGeom->GetShape() )->_is_nil() ); // check TopoDS
2768       if ( !isValidGeom ) // check reference
2769       {
2770         isValidGeom = ( ! groupSO->_is_nil() &&
2771                         groupSO->FindSubObject( SMESH::Tag_RefOnShape, refSO.inout() ) &&
2772                         refSO->ReferencedObject( geomSO.inout() ) &&
2773                         ! geomSO->_is_nil() &&
2774                         !CORBA::is_nil( CORBA::Object_var( geomSO->GetObject() )));
2775       }
2776     }
2777     else if ( !onFilt->_is_nil() )
2778     {
2779       isValidGeom = isValidGeomFilter( onFilt->GetFilter() );
2780     }
2781     else // standalone
2782     {
2783       isValidGeom = ( !groupSO->_is_nil() &&
2784                       !groupSO->FindSubObject( SMESH::Tag_RefOnShape, refSO.inout() ));
2785     }
2786     if ( !isValidGeom )
2787     {
2788       if ( !IsLoaded() || group->IsEmpty() )
2789       {
2790         RemoveGroup( group );
2791       }
2792       else if ( !onGeom->_is_nil() || !onFilt->_is_nil() )
2793       {
2794         SMESH::SMESH_Group_var ( ConvertToStandalone( group ));
2795       }
2796       else // is it possible?
2797       {
2798         builder->RemoveObjectWithChildren( refSO );
2799       }
2800     }
2801   }
2802
2803
2804   if ( !_impl->HasShapeToMesh() ) return;
2805
2806   SMESH::smIdType nbEntities = NbNodes() + NbElements();
2807
2808   // Check if group contents changed
2809
2810   typedef map< string, TopoDS_Shape > TEntry2Geom;
2811   TEntry2Geom newGroupContents;
2812
2813   list<TGeomGroupData>::iterator
2814     data = _geomGroupData.begin(), dataEnd = _geomGroupData.end();
2815   for ( ; data != dataEnd; ++data )
2816   {
2817     pair< TEntry2Geom::iterator, bool > it_new =
2818       newGroupContents.insert( make_pair( data->_groupEntry, TopoDS_Shape() ));
2819     bool processedGroup    = !it_new.second;
2820     TopoDS_Shape& newShape = it_new.first->second;
2821     if ( !processedGroup )
2822       newShape = newGroupShape( *data, ONLY_IF_CHANGED );
2823     if ( newShape.IsNull() )
2824       continue; // no changes
2825
2826     if ( _preMeshInfo )
2827       _preMeshInfo->ForgetOrLoad();
2828
2829     if ( processedGroup ) { // update group indices
2830       list<TGeomGroupData>::iterator data2 = data;
2831       for ( --data2; data2->_groupEntry != data->_groupEntry; --data2) {}
2832       data->_indices = data2->_indices;
2833     }
2834
2835     // Update SMESH objects according to new GEOM group contents
2836
2837     SMESH::SMESH_subMesh_var submesh = SMESH::SMESH_subMesh::_narrow( data->_smeshObject );
2838     if ( !submesh->_is_nil() ) // -------------- Sub mesh ---------------------
2839     {
2840       int oldID = submesh->GetId();
2841       if ( !_mapSubMeshIor.count( oldID ))
2842         continue;
2843       TopoDS_Shape oldShape = _mapSubMesh[oldID]->GetSubShape();
2844
2845       // update hypotheses
2846       list <const SMESHDS_Hypothesis * > hyps = _impl->GetHypothesisList(oldShape);
2847       list <const SMESHDS_Hypothesis * >::iterator hypIt;
2848       for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2849       {
2850         _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
2851         _impl->AddHypothesis   ( newShape, (*hypIt)->GetID());
2852       }
2853       // care of submeshes
2854       SMESH_subMesh* newSubmesh = _impl->GetSubMesh( newShape );
2855       int newID = newSubmesh->GetId();
2856       if ( newID != oldID ) {
2857         _mapSubMesh   [ newID ] = newSubmesh;
2858         _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2859         _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2860         _mapSubMesh.   erase(oldID);
2861         _mapSubMesh_i. erase(oldID);
2862         _mapSubMeshIor.erase(oldID);
2863         _mapSubMesh_i [ newID ]->changeLocalId( newID );
2864       }
2865       continue;
2866     }
2867
2868     SMESH::SMESH_GroupOnGeom_var smeshGroup =
2869       SMESH::SMESH_GroupOnGeom::_narrow( data->_smeshObject );
2870     if ( !smeshGroup->_is_nil() ) // ------------ GROUP -----------------------
2871     {
2872       SMESH_GroupOnGeom_i* group_i = SMESH::DownCast<SMESH_GroupOnGeom_i*>( smeshGroup );
2873       if ( group_i ) {
2874         ::SMESH_Group* group = _impl->GetGroup( group_i->GetLocalID() );
2875         SMESHDS_GroupOnGeom* ds = static_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() );
2876         ds->SetShape( newShape );
2877       }
2878       continue;
2879     }
2880
2881     SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( data->_smeshObject );
2882     if ( !mesh->_is_nil() ) // -------------- MESH ----------------------------
2883     {
2884       // Remove groups and submeshes basing on removed sub-shapes
2885
2886       TopTools_MapOfShape newShapeMap;
2887       TopoDS_Iterator shapeIt( newShape );
2888       for ( ; shapeIt.More(); shapeIt.Next() )
2889         newShapeMap.Add( shapeIt.Value() );
2890
2891       SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
2892       for ( shapeIt.Initialize( meshDS->ShapeToMesh() ); shapeIt.More(); shapeIt.Next() )
2893       {
2894         if ( newShapeMap.Contains( shapeIt.Value() ))
2895           continue;
2896         TopTools_IndexedMapOfShape oldShapeMap;
2897         TopExp::MapShapes( shapeIt.Value(), oldShapeMap );
2898         for ( int i = 1; i <= oldShapeMap.Extent(); ++i )
2899         {
2900           const TopoDS_Shape& oldShape = oldShapeMap(i);
2901           int oldInd = meshDS->ShapeToIndex( oldShape );
2902           // -- submeshes --
2903           map<int, SMESH::SMESH_subMesh_ptr>::iterator i_smIor = _mapSubMeshIor.find( oldInd );
2904           if ( i_smIor != _mapSubMeshIor.end() ) {
2905             RemoveSubMesh( i_smIor->second ); // one submesh per shape index
2906           }
2907           // --- groups ---
2908           map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.begin();
2909           for ( ; i_grp != _mapGroups.end(); ++i_grp )
2910           {
2911             // check if a group bases on oldInd shape
2912             SMESHDS_GroupOnGeom* grpOnGeom = 0;
2913             if ( ::SMESH_Group* g = _impl->GetGroup( i_grp->first ))
2914               grpOnGeom = dynamic_cast<SMESHDS_GroupOnGeom*>( g->GetGroupDS() );
2915             if ( grpOnGeom && oldShape.IsSame( grpOnGeom->GetShape() ))
2916             { // remove
2917               RemoveGroup( i_grp->second ); // several groups can base on same shape
2918               i_grp = _mapGroups.begin(); // _mapGroups changed - restart iteration
2919             }
2920           }
2921         }
2922       }
2923       // Reassign hypotheses and update groups after setting the new shape to mesh
2924
2925       // collect anassigned hypotheses
2926       typedef list< pair< TIndexedShape, list<const SMESHDS_Hypothesis*> > > TShapeHypList;
2927       list <const SMESHDS_Hypothesis * >::const_iterator hypIt;
2928       TShapeHypList assignedHyps;
2929       for ( int i = 1; i <= meshDS->MaxShapeIndex(); ++i )
2930       {
2931         const TopoDS_Shape& oldShape = meshDS->IndexToShape(i);
2932         list<const SMESHDS_Hypothesis*> hyps = meshDS->GetHypothesis( oldShape );// copy
2933         if ( !hyps.empty() ) {
2934           assignedHyps.push_back( make_pair( TIndexedShape(i,oldShape), hyps ));
2935           for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2936             _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
2937         }
2938       }
2939       // collect shapes supporting groups
2940       typedef list < pair< TIndexedShape, SMDSAbs_ElementType > > TShapeTypeList;
2941       TShapeTypeList groupData;
2942       const set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
2943       set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2944       for ( ; grIt != groups.end(); ++grIt )
2945       {
2946         if ( SMESHDS_GroupOnGeom* gog = dynamic_cast<SMESHDS_GroupOnGeom*>( *grIt ))
2947           groupData.push_back
2948             ( make_pair( TIndexedShape( gog->GetID(),gog->GetShape()), gog->GetType()));
2949       }
2950       // set new shape to mesh -> DS of sub-meshes and geom groups is deleted
2951       _impl->Clear();
2952       _impl->ShapeToMesh( TopoDS_Shape() ); // IPAL52730
2953       _impl->ShapeToMesh( newShape );
2954
2955       // reassign hypotheses
2956       TShapeHypList::iterator indS_hyps = assignedHyps.begin();
2957       for ( ; indS_hyps != assignedHyps.end(); ++indS_hyps )
2958       {
2959         TIndexedShape&                   geom = indS_hyps->first;
2960         list<const SMESHDS_Hypothesis*>& hyps = indS_hyps->second;
2961         int oldID = geom._index;
2962         int newID = meshDS->ShapeToIndex( geom._shape );
2963         if ( oldID == 1 ) { // main shape
2964           newID = 1;
2965           geom._shape = newShape;
2966         }
2967         if ( !newID )
2968           continue;
2969         for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2970           _impl->AddHypothesis( geom._shape, (*hypIt)->GetID());
2971         // care of sub-meshes
2972         SMESH_subMesh* newSubmesh = _impl->GetSubMesh( geom._shape );
2973         if ( newID != oldID ) {
2974           _mapSubMesh   [ newID ] = newSubmesh;
2975           _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2976           _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2977           _mapSubMesh.   erase(oldID);
2978           _mapSubMesh_i. erase(oldID);
2979           _mapSubMeshIor.erase(oldID);
2980           _mapSubMesh_i [ newID ]->changeLocalId( newID );
2981         }
2982       }
2983       // recreate groups
2984       TShapeTypeList::iterator geomType = groupData.begin();
2985       for ( ; geomType != groupData.end(); ++geomType )
2986       {
2987         const TIndexedShape& geom = geomType->first;
2988         int oldID = geom._index;
2989         if ( _mapGroups.find( oldID ) == _mapGroups.end() )
2990           continue;
2991         // get group name
2992         SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( _mapGroups[oldID] );
2993         CORBA::String_var      name    = groupSO->GetName();
2994         // update
2995         if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>(_mapGroups[oldID]))
2996           if ( SMESH_Group* group = _impl->AddGroup( geomType->second, name.in(),
2997                                                      /*id=*/-1, geom._shape ))
2998             group_i->changeLocalId( group->GetID() );
2999       }
3000
3001       break; // everything has been updated
3002
3003     } // update mesh
3004   } // loop on group data
3005
3006   // Update icons
3007
3008   SMESH::smIdType newNbEntities = NbNodes() + NbElements();
3009   list< SALOMEDS::SObject_wrap > soToUpdateIcons;
3010   if ( newNbEntities != nbEntities )
3011   {
3012     // Add all SObjects with icons to soToUpdateIcons
3013     soToUpdateIcons.push_back( _gen_i->ObjectToSObject( _this() )); // mesh
3014
3015     for (map<int, SMESH::SMESH_subMesh_ptr>::iterator i_sm = _mapSubMeshIor.begin();
3016          i_sm != _mapSubMeshIor.end(); ++i_sm ) // submeshes
3017       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( i_sm->second ));
3018
3019     for ( map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
3020           i_gr != _mapGroups.end(); ++i_gr ) // groups
3021       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( i_gr->second ));
3022   }
3023
3024   list< SALOMEDS::SObject_wrap >::iterator so = soToUpdateIcons.begin();
3025   for ( ; so != soToUpdateIcons.end(); ++so )
3026     _gen_i->SetPixMap( *so, "ICON_SMESH_TREE_MESH_WARN" );
3027 }
3028
3029 //=============================================================================
3030 /*!
3031  * \brief Create standalone group from a group on geometry or filter
3032  */
3033 //=============================================================================
3034
3035 SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupBase_ptr theGroup )
3036 {
3037   SMESH::SMESH_Group_var aGroup;
3038
3039   SMESH_TRY;
3040
3041   if ( _preMeshInfo )
3042     _preMeshInfo->FullLoadFromFile();
3043
3044   if ( theGroup->_is_nil() )
3045     return aGroup._retn();
3046
3047   SMESH_GroupBase_i* aGroupToRem = SMESH::DownCast<SMESH_GroupBase_i*>( theGroup );
3048   if ( !aGroupToRem )
3049     return aGroup._retn();
3050
3051   const bool isOnFilter = ( SMESH::DownCast< SMESH_GroupOnFilter_i* > ( theGroup ));
3052
3053   const int anId = aGroupToRem->GetLocalID();
3054   if ( !_impl->ConvertToStandalone( anId ) )
3055     return aGroup._retn();
3056   removeGeomGroupData( theGroup );
3057
3058   SMESH_GroupBase_i* aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
3059
3060   // remove old instance of group from own map
3061   { SMESH::SMESH_GroupBase_var var( _mapGroups[anId] ); } // decref CORBA object
3062   _mapGroups.erase( anId );
3063
3064   SALOMEDS::StudyBuilder_var builder;
3065   SALOMEDS::SObject_wrap     aGroupSO;
3066   SALOMEDS::Study_var        aStudy = SMESH_Gen_i::GetSMESHGen()->getStudyServant();
3067   if ( !aStudy->_is_nil() ) {
3068     builder  = aStudy->NewBuilder();
3069     aGroupSO = _gen_i->ObjectToSObject( theGroup );
3070     if ( !aGroupSO->_is_nil() )
3071     {
3072       // remove reference to geometry
3073       SALOMEDS::ChildIterator_wrap chItr = aStudy->NewChildIterator(aGroupSO);
3074       for ( ; chItr->More(); chItr->Next() )
3075       {
3076         // Remove group's child SObject
3077         SALOMEDS::SObject_wrap so = chItr->Value();
3078         builder->RemoveObject( so );
3079       }
3080       // Update Python script
3081       TPythonDump() << aGroupSO << " = " << SMESH::SMESH_Mesh_var(_this())
3082                     << ".ConvertToStandalone( " << aGroupSO << " )";
3083
3084       // change icon of Group on Filter
3085       if ( isOnFilter )
3086       {
3087         // SMESH::array_of_ElementType_var elemTypes = aGroupImpl->GetTypes();
3088         // const int isEmpty = ( elemTypes->length() == 0 );
3089         // if ( !isEmpty )
3090         {
3091           SALOMEDS::GenericAttribute_wrap anAttr =
3092             builder->FindOrCreateAttribute( aGroupSO, "AttributePixMap" );
3093           SALOMEDS::AttributePixMap_wrap pm = anAttr;
3094           pm->SetPixMap( "ICON_SMESH_TREE_GROUP" );
3095         }
3096       }
3097     }
3098   }
3099
3100   // remember new group in own map
3101   aGroup = SMESH::SMESH_Group::_narrow( aGroupImpl->_this() );
3102   _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
3103
3104   // register CORBA object for persistence
3105   _gen_i->RegisterObject( aGroup );
3106
3107   CORBA::String_var ior = _gen_i->GetORB()->object_to_string( aGroup );
3108   builder->SetIOR( aGroupSO, ior.in() ); //  == aGroup->Register();
3109   //aGroup->Register();
3110   aGroupToRem->UnRegister();
3111
3112   SMESH_CATCH( SMESH::throwCorbaException );
3113
3114   return aGroup._retn();
3115 }
3116
3117 //================================================================================
3118 /*!
3119  * \brief Create a sub-mesh on a given sub-shape
3120  */
3121 //================================================================================
3122
3123 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::createSubMesh( GEOM::GEOM_Object_ptr theSubShapeObject )
3124 {
3125   if(MYDEBUG) MESSAGE( "createSubMesh" );
3126   TopoDS_Shape  myLocSubShape = _gen_i->GeomObjectToShape(theSubShapeObject);
3127   ::SMESH_subMesh * mySubMesh = _impl->GetSubMesh(myLocSubShape);
3128   int               subMeshId = 0;
3129
3130   SMESH_subMesh_i * subMeshServant;
3131   if ( mySubMesh )
3132   {
3133     subMeshId = mySubMesh->GetId();
3134     subMeshServant = new SMESH_subMesh_i(myPOA, _gen_i, this, subMeshId);
3135   }
3136   else // "invalid sub-mesh"
3137   {
3138     // The invalid sub-mesh is created for the case where a valid sub-shape not found
3139     // by SMESH_Gen_i::CopyMeshWithGeom(). The invalid sub-mesh has GetId() < 0.
3140     if ( _mapSubMesh.empty() )
3141       subMeshId = -1;
3142     else
3143       subMeshId = _mapSubMesh.begin()->first - 1;
3144     subMeshServant = new SMESH_Invalid_subMesh_i(myPOA, _gen_i, this, subMeshId, theSubShapeObject);
3145   }
3146
3147   SMESH::SMESH_subMesh_var subMesh = subMeshServant->_this();
3148
3149   _mapSubMesh   [subMeshId] = mySubMesh;
3150   _mapSubMesh_i [subMeshId] = subMeshServant;
3151   _mapSubMeshIor[subMeshId] = SMESH::SMESH_subMesh::_duplicate( subMesh );
3152
3153   subMeshServant->Register();
3154
3155   // register CORBA object for persistence
3156   int nextId = _gen_i->RegisterObject( subMesh );
3157   if(MYDEBUG) { MESSAGE( "Add submesh to map with id = "<< nextId); }
3158   else        { (void)nextId; } // avoid "unused variable" warning
3159
3160   // to track changes of GEOM groups
3161   if ( subMeshId > 0 )
3162     addGeomGroupData( theSubShapeObject, subMesh );
3163
3164   return subMesh._retn();
3165 }
3166
3167 //================================================================================
3168 /*!
3169  * \brief Return an existing sub-mesh based on a sub-shape with the given ID
3170  */
3171 //================================================================================
3172
3173 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::getSubMesh(int shapeID)
3174 {
3175   map<int, SMESH::SMESH_subMesh_ptr>::iterator it = _mapSubMeshIor.find( shapeID );
3176   if ( it == _mapSubMeshIor.end() )
3177     return SMESH::SMESH_subMesh::_nil();
3178
3179   return SMESH::SMESH_subMesh::_duplicate( (*it).second );
3180 }
3181
3182 //================================================================================
3183 /*!
3184  * \brief Remove a sub-mesh based on the given sub-shape
3185  */
3186 //================================================================================
3187
3188 bool SMESH_Mesh_i::removeSubMesh (SMESH::SMESH_subMesh_ptr theSubMesh,
3189                                   GEOM::GEOM_Object_ptr    theSubShapeObject )
3190 {
3191   bool isHypChanged = false;
3192   if ( theSubMesh->_is_nil() /*|| theSubShapeObject->_is_nil()*/ )
3193     return isHypChanged;
3194
3195   const int subMeshId = theSubMesh->GetId();
3196
3197   if ( theSubShapeObject->_is_nil() )  // not published shape (IPAL13617)
3198   {
3199     SMESH_subMesh* sm;
3200     if (( _mapSubMesh.count( subMeshId )) &&
3201         ( sm = _impl->GetSubMeshContaining( subMeshId )))
3202     {
3203       TopoDS_Shape S = sm->GetSubShape();
3204       if ( !S.IsNull() )
3205       {
3206         list<const SMESHDS_Hypothesis*> hyps = _impl->GetHypothesisList( S );
3207         isHypChanged = !hyps.empty();
3208         if ( isHypChanged && _preMeshInfo )
3209           _preMeshInfo->ForgetOrLoad();
3210         list<const SMESHDS_Hypothesis*>::const_iterator hyp = hyps.begin();
3211         for ( ; hyp != hyps.end(); ++hyp )
3212           _impl->RemoveHypothesis(S, (*hyp)->GetID());
3213       }
3214     }
3215   }
3216   else
3217   {
3218     try {
3219       SMESH::ListOfHypothesis_var aHypList = GetHypothesisList( theSubShapeObject );
3220       isHypChanged = ( aHypList->length() > 0 );
3221       for ( int i = 0, n = aHypList->length(); i < n; i++ ) {
3222         removeHypothesis( theSubShapeObject, aHypList[i] );
3223       }
3224     }
3225     catch( const SALOME::SALOME_Exception& ) {
3226       INFOS("SMESH_Mesh_i::removeSubMesh(): exception caught!");
3227     }
3228     removeGeomGroupData( theSubShapeObject );
3229   }
3230
3231   // remove a servant
3232   std::map<int, SMESH_subMesh_i*>::iterator id_smi = _mapSubMesh_i.find( subMeshId );
3233   if ( id_smi != _mapSubMesh_i.end() )
3234     id_smi->second->UnRegister();
3235
3236   // remove a CORBA object
3237   std::map<int, SMESH::SMESH_subMesh_ptr>::iterator id_smptr = _mapSubMeshIor.find( subMeshId );
3238   if ( id_smptr != _mapSubMeshIor.end() )
3239     SMESH::SMESH_subMesh_var( id_smptr->second );
3240
3241   _mapSubMesh.erase(subMeshId);
3242   _mapSubMesh_i.erase(subMeshId);
3243   _mapSubMeshIor.erase(subMeshId);
3244
3245   return isHypChanged;
3246 }
3247
3248 //================================================================================
3249 /*!
3250  * \brief Create a group. Group type depends on given arguments
3251  */
3252 //================================================================================
3253
3254 SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType        theElemType,
3255                                                       const char*               theName,
3256                                                       const int                 theID,
3257                                                       const TopoDS_Shape&       theShape,
3258                                                       const SMESH_PredicatePtr& thePredicate )
3259 {
3260   std::string newName;
3261   if ( !theName || !theName[0] )
3262   {
3263     std::set< std::string > presentNames;
3264     std::map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator i_gr = _mapGroups.begin();
3265     for ( ; i_gr != _mapGroups.end(); ++i_gr )
3266     {
3267       CORBA::String_var name = i_gr->second->GetName();
3268       presentNames.insert( name.in() );
3269     }
3270     do {
3271       newName = "noname_Group_" + SMESH_Comment( presentNames.size() + 1 );
3272     } while ( !presentNames.insert( newName ).second );
3273     theName = newName.c_str();
3274   }
3275   SMESH::SMESH_GroupBase_var aGroup;
3276   if ( SMESH_Group* g = _impl->AddGroup( (SMDSAbs_ElementType)theElemType, theName,
3277                                          theID, theShape, thePredicate ))
3278   {
3279     int anId = g->GetID();
3280     SMESH_GroupBase_i* aGroupImpl;
3281     if ( !theShape.IsNull() )
3282       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
3283     else if ( thePredicate )
3284       aGroupImpl = new SMESH_GroupOnFilter_i( SMESH_Gen_i::GetPOA(), this, anId );
3285     else
3286       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
3287
3288     aGroup = aGroupImpl->_this();
3289     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
3290     aGroupImpl->Register();
3291
3292     // register CORBA object for persistence
3293     int nextId = _gen_i->RegisterObject( aGroup );
3294     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
3295     else        { nextId = ( nextId > 0 ); } // avoid "unused variable" warning in release mode
3296
3297     // to track changes of GEOM groups
3298     if ( !theShape.IsNull() ) {
3299       GEOM::GEOM_Object_var geom = _gen_i->ShapeToGeomObject( theShape );
3300       addGeomGroupData( geom, aGroup );
3301     }
3302   }
3303   return aGroup._retn();
3304 }
3305
3306 //=============================================================================
3307 /*!
3308  * SMESH_Mesh_i::removeGroup
3309  *
3310  * Should be called by ~SMESH_Group_i()
3311  */
3312 //=============================================================================
3313
3314 void SMESH_Mesh_i::removeGroup( const int theId )
3315 {
3316   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::removeGroup()" );
3317   if ( _mapGroups.find( theId ) != _mapGroups.end() ) {
3318     SMESH::SMESH_GroupBase_var group = _mapGroups[theId];
3319     _mapGroups.erase( theId );
3320     removeGeomGroupData( group );
3321     if ( !_impl->RemoveGroup( theId ))
3322     {
3323       // it seems to be a call up from _impl caused by hyp modification (issue 0020918)
3324       RemoveGroup( group );
3325     }
3326     group->UnRegister();
3327   }
3328 }
3329
3330 //================================================================================
3331 /*!
3332  * \brief Return a log that can be used to move another mesh to the same state as this one
3333  */
3334 //================================================================================
3335
3336 SMESH::log_array * SMESH_Mesh_i::GetLog(CORBA::Boolean clearAfterGet)
3337 {
3338   SMESH::log_array_var aLog;
3339
3340   SMESH_TRY;
3341   if ( _preMeshInfo )
3342     _preMeshInfo->FullLoadFromFile();
3343
3344   list < SMESHDS_Command * >logDS = _impl->GetLog();
3345   aLog = new SMESH::log_array;
3346   int indexLog = 0;
3347   int lg = logDS.size();
3348   aLog->length(lg);
3349   list < SMESHDS_Command * >::iterator its = logDS.begin();
3350   while(its != logDS.end()){
3351     SMESHDS_Command *com = *its;
3352     int comType = com->GetType();
3353     smIdType lgcom = com->GetNumber();
3354     const list < smIdType >&intList = com->GetIndexes();
3355     int inum = intList.size();
3356     list < smIdType >::const_iterator ii = intList.begin();
3357     const list < double >&coordList = com->GetCoords();
3358     int rnum = coordList.size();
3359     list < double >::const_iterator ir = coordList.begin();
3360     aLog[indexLog].commandType = comType;
3361     aLog[indexLog].number = lgcom;
3362     aLog[indexLog].coords.length(rnum);
3363     aLog[indexLog].indexes.length(inum);
3364     for(int i = 0; i < rnum; i++){
3365       aLog[indexLog].coords[i] = *ir;
3366       ir++;
3367     }
3368     for(int i = 0; i < inum; i++){
3369       aLog[indexLog].indexes[i] = *ii;
3370       ii++;
3371     }
3372     indexLog++;
3373     its++;
3374   }
3375   if(clearAfterGet)
3376     _impl->ClearLog();
3377
3378   SMESH_CATCH( SMESH::throwCorbaException );
3379
3380   return aLog._retn();
3381 }
3382
3383 //================================================================================
3384 /*!
3385  * \brief Remove the log of commands
3386  */
3387 //================================================================================
3388
3389 void SMESH_Mesh_i::ClearLog()
3390 {
3391   SMESH_TRY;
3392   _impl->ClearLog();
3393   SMESH_CATCH( SMESH::throwCorbaException );
3394 }
3395
3396 //================================================================================
3397 /*!
3398  * \brief Return a mesh ID
3399  */
3400 //================================================================================
3401
3402 CORBA::Long SMESH_Mesh_i::GetId()
3403 {
3404   return _id;
3405 }
3406
3407 //=============================================================================
3408 namespace
3409 {
3410   //!< implementation of struct used to call methods of SMESH_Mesh_i from SMESH_Mesh
3411   // issue 0020918: groups removal is caused by hyp modification
3412   // issue 0021208: to forget not loaded mesh data at hyp modification
3413   struct TCallUp_i : public SMESH_Mesh::TCallUp
3414   {
3415     SMESH_Mesh_i* _mesh;
3416     TCallUp_i(SMESH_Mesh_i* mesh):_mesh(mesh) {}
3417     void RemoveGroup (const int theGroupID) override { _mesh->removeGroup( theGroupID ); }
3418     void HypothesisModified( int hypID,
3419                              bool updIcons) override { _mesh->onHypothesisModified( hypID,
3420                                                                                     updIcons ); }
3421     void Load ()                            override { _mesh->Load(); }
3422     bool IsLoaded()                         override { return _mesh->IsLoaded(); }
3423     TopoDS_Shape GetShapeByEntry(const std::string& entry) override
3424     {
3425       GEOM::GEOM_Object_var go = SMESH_Gen_i::GetGeomObjectByEntry( entry );
3426       return SMESH_Gen_i::GeomObjectToShape( go );
3427     }
3428   };
3429 }
3430
3431 //================================================================================
3432 /*!
3433  * \brief callback from _impl to
3434  *     1) forget not loaded mesh data (issue 0021208)
3435  *     2) mark hypothesis as valid
3436  */
3437 //================================================================================
3438
3439 void SMESH_Mesh_i::onHypothesisModified(int theHypID, bool theUpdateIcons)
3440 {
3441   if ( _preMeshInfo )
3442     _preMeshInfo->ForgetOrLoad();
3443
3444   if ( theUpdateIcons )
3445   {
3446     SMESH::SMESH_Mesh_var mesh = _this();
3447     _gen_i->UpdateIcons( mesh );
3448   }
3449
3450   if ( _nbInvalidHypos != 0 )
3451   {
3452     // mark a hypothesis as valid after edition
3453     int nbInvalid = 0;
3454     SALOMEDS::SComponent_wrap smeshComp = _gen_i->PublishComponent();
3455     SALOMEDS::SObject_wrap hypRoot;
3456     if ( !smeshComp->_is_nil() &&
3457          smeshComp->FindSubObject( _gen_i->GetHypothesisRootTag(), hypRoot.inout() ))
3458     {
3459       SALOMEDS::ChildIterator_wrap anIter = _gen_i->getStudyServant()->NewChildIterator( hypRoot );
3460       for ( ; anIter->More(); anIter->Next() )
3461       {
3462         SALOMEDS::SObject_wrap    hypSO = anIter->Value();
3463         CORBA::Object_var           obj = _gen_i->SObjectToObject( hypSO );
3464         SMESH::SMESH_Hypothesis_var hyp = SMESH::SMESH_Hypothesis::_narrow( obj );
3465         if ( !hyp->_is_nil() && hyp->GetId() == theHypID )
3466           _gen_i->HighLightInvalid( hyp, false );
3467         else
3468           nbInvalid += _gen_i->IsInvalid( hypSO );
3469       }
3470     }
3471     _nbInvalidHypos = nbInvalid;
3472   }
3473 }
3474
3475 //================================================================================
3476 /*!
3477  * \brief Set mesh implementation
3478  */
3479 //================================================================================
3480
3481 void SMESH_Mesh_i::SetImpl(::SMESH_Mesh * impl)
3482 {
3483   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::SetImpl");
3484   _impl = impl;
3485   if ( _impl )
3486     _impl->SetCallUp( new TCallUp_i(this));
3487 }
3488
3489 //=============================================================================
3490 /*!
3491  * Return a mesh implementation
3492  */
3493 //=============================================================================
3494
3495 ::SMESH_Mesh & SMESH_Mesh_i::GetImpl()
3496 {
3497   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::GetImpl()");
3498   return *_impl;
3499 }
3500
3501 //=============================================================================
3502 /*!
3503  * Return mesh editor
3504  */
3505 //=============================================================================
3506
3507 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditor()
3508 {
3509   SMESH::SMESH_MeshEditor_var aMeshEdVar;
3510
3511   SMESH_TRY;
3512   if ( _preMeshInfo )
3513     _preMeshInfo->FullLoadFromFile();
3514
3515   // Create MeshEditor
3516   if ( !_editor )
3517     _editor = new SMESH_MeshEditor_i( this, false );
3518   aMeshEdVar = _editor->_this();
3519
3520   // Update Python script
3521   TPythonDump() << _editor << " = "
3522                 << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshEditor()";
3523
3524   SMESH_CATCH( SMESH::throwCorbaException );
3525
3526   return aMeshEdVar._retn();
3527 }
3528
3529 //=============================================================================
3530 /*!
3531  * Return mesh edition previewer
3532  */
3533 //=============================================================================
3534
3535 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditPreviewer()
3536 {
3537   SMESH::SMESH_MeshEditor_var aMeshEdVar;
3538
3539   SMESH_TRY;
3540   if ( _preMeshInfo )
3541     _preMeshInfo->FullLoadFromFile();
3542
3543   if ( !_previewEditor )
3544     _previewEditor = new SMESH_MeshEditor_i( this, true );
3545   aMeshEdVar = _previewEditor->_this();
3546
3547   SMESH_CATCH( SMESH::throwCorbaException );
3548
3549   return aMeshEdVar._retn();
3550 }
3551
3552 //================================================================================
3553 /*!
3554  * \brief Return true if the mesh has been edited since a last total re-compute
3555  *        and those modifications may prevent successful partial re-compute
3556  */
3557 //================================================================================
3558
3559 CORBA::Boolean SMESH_Mesh_i::HasModificationsToDiscard()
3560 {
3561   Unexpect aCatch(SALOME_SalomeException);
3562   return _impl->HasModificationsToDiscard();
3563 }
3564
3565 //================================================================================
3566 /*!
3567  * \brief Return a random unique color
3568  */
3569 //================================================================================
3570
3571 static SALOMEDS::Color getUniqueColor( const std::list<SALOMEDS::Color>& theReservedColors )
3572 {
3573   const int MAX_ATTEMPTS = 100;
3574   int cnt = 0;
3575   double tolerance = 0.5;
3576   SALOMEDS::Color col;
3577
3578   bool ok = false;
3579   while ( !ok ) {
3580     // generate random color
3581     double red    = (double)rand() / RAND_MAX;
3582     double green  = (double)rand() / RAND_MAX;
3583     double blue   = (double)rand() / RAND_MAX;
3584     // check existence in the list of the existing colors
3585     bool matched = false;
3586     std::list<SALOMEDS::Color>::const_iterator it;
3587     for ( it = theReservedColors.begin(); it != theReservedColors.end() && !matched; ++it ) {
3588       SALOMEDS::Color color = *it;
3589       double tol = fabs( color.R - red ) + fabs( color.G - green ) + fabs( color.B  - blue  );
3590       matched = tol < tolerance;
3591     }
3592     if ( (cnt+1) % 20 == 0 ) tolerance = tolerance/2;
3593     ok = ( ++cnt == MAX_ATTEMPTS ) || !matched;
3594     col.R = red;
3595     col.G = green;
3596     col.B = blue;
3597   }
3598   return col;
3599 }
3600
3601 //=============================================================================
3602 /*!
3603  * Set auto-color mode. If it is on, groups get unique random colors
3604  */
3605 //=============================================================================
3606
3607 void SMESH_Mesh_i::SetAutoColor(CORBA::Boolean theAutoColor)
3608 {
3609   Unexpect aCatch(SALOME_SalomeException);
3610   _impl->SetAutoColor(theAutoColor);
3611
3612   TPythonDump pyDump; // not to dump group->SetColor() from below code
3613   pyDump << SMESH::SMESH_Mesh_var(_this()) <<".SetAutoColor( "<<theAutoColor<<" )";
3614
3615   std::list<SALOMEDS::Color> aReservedColors;
3616   map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.begin();
3617   for ( ; it != _mapGroups.end(); it++ ) {
3618     if ( CORBA::is_nil( it->second )) continue;
3619     SALOMEDS::Color aColor = getUniqueColor( aReservedColors );
3620     it->second->SetColor( aColor );
3621     aReservedColors.push_back( aColor );
3622   }
3623 }
3624
3625 //=============================================================================
3626 /*!
3627  * Return true if auto-color mode is on
3628  */
3629 //=============================================================================
3630
3631 CORBA::Boolean SMESH_Mesh_i::GetAutoColor()
3632 {
3633   Unexpect aCatch(SALOME_SalomeException);
3634   return _impl->GetAutoColor();
3635 }
3636
3637 //=============================================================================
3638 /*!
3639  *  Check if there are groups with equal names
3640  */
3641 //=============================================================================
3642
3643 CORBA::Boolean SMESH_Mesh_i::HasDuplicatedGroupNamesMED()
3644 {
3645   return _impl->HasDuplicatedGroupNamesMED();
3646 }
3647
3648 //================================================================================
3649 /*!
3650  * \brief Care of a file before exporting mesh into it
3651  */
3652 //================================================================================
3653
3654 void SMESH_Mesh_i::PrepareForWriting (const char* file, bool overwrite)
3655 {
3656   SMESH_File aFile( file, false );
3657   SMESH_Comment msg;
3658   if ( aFile.exists() ) {
3659     // existing filesystem node
3660     if ( !aFile.isDirectory() ) {
3661       if ( aFile.openForWriting() ) {
3662         if ( overwrite && ! aFile.remove()) {
3663           msg << "Can't replace " << aFile.getName();
3664         }
3665       } else {
3666         msg << "Can't write into " << aFile.getName();
3667       }
3668     } else {
3669       msg << "Location " << aFile.getName() << " is not a file";
3670     }
3671   }
3672   else {
3673     // nonexisting file; check if it can be created
3674     if ( !aFile.openForWriting() ) {
3675       msg << "You cannot create the file "
3676           << aFile.getName()
3677           << ". Check the directory existence and access rights";
3678     }
3679     aFile.remove();
3680   }
3681
3682   if ( !msg.empty() )
3683   {
3684     msg << ".";
3685     THROW_SALOME_CORBA_EXCEPTION(msg.c_str(), SALOME::BAD_PARAM);
3686   }
3687 }
3688
3689 /*!
3690   Return a MeshName
3691  */
3692 std::string SMESH_Mesh_i::generateMeshName()
3693 {
3694   string aMeshName = "Mesh";
3695   SALOMEDS::Study_var aStudy = SMESH_Gen_i::GetSMESHGen()->getStudyServant();
3696   if ( !aStudy->_is_nil() )
3697   {
3698     SALOMEDS::SObject_wrap aMeshSO = _gen_i->ObjectToSObject(  _this() );
3699     if ( !aMeshSO->_is_nil() )
3700     {
3701       CORBA::String_var name = aMeshSO->GetName();
3702       aMeshName = name;
3703     }
3704   }
3705   return aMeshName;
3706 }
3707
3708 //================================================================================
3709 /*!
3710  * \brief Prepare a file for export and pass names of mesh groups from study to mesh DS
3711  *  \param file - file name
3712  *  \param overwrite - to erase the file or not
3713  *  \retval string - mesh name
3714  */
3715 //================================================================================
3716
3717 string SMESH_Mesh_i::prepareMeshNameAndGroups(const char*    file,
3718                                               CORBA::Boolean overwrite)
3719 {
3720   // Perform Export
3721   PrepareForWriting(file, overwrite);
3722   string aMeshName(this->generateMeshName());
3723   SALOMEDS::Study_var aStudy = SMESH_Gen_i::GetSMESHGen()->getStudyServant();
3724   if ( !aStudy->_is_nil() ) {
3725     SALOMEDS::SObject_wrap aMeshSO = _gen_i->ObjectToSObject(  _this() );
3726     if ( !aMeshSO->_is_nil() ) {
3727       // asv : 27.10.04 : fix of 6903: check for StudyLocked before adding attributes
3728       if ( !aStudy->GetProperties()->IsLocked() )
3729       {
3730         SALOMEDS::GenericAttribute_wrap anAttr;
3731         SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder();
3732         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeExternalFileDef");
3733         SALOMEDS::AttributeExternalFileDef_wrap aFileName = anAttr;
3734         ASSERT(!aFileName->_is_nil());
3735         aFileName->SetValue(file);
3736         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeFileType");
3737         SALOMEDS::AttributeFileType_wrap aFileType = anAttr;
3738         ASSERT(!aFileType->_is_nil());
3739         aFileType->SetValue("FICHIERMED");
3740       }
3741     }
3742   }
3743   // Update Python script
3744   // set name of mesh before export
3745   TPythonDump() << _gen_i << ".SetName("
3746                 << SMESH::SMESH_Mesh_var(_this()) << ", '" << aMeshName.c_str() << "')";
3747
3748   // check names of groups
3749   checkGroupNames();
3750
3751   return aMeshName;
3752 }
3753
3754 //================================================================================
3755 /*!
3756  * \brief Export to MED file
3757  */
3758 //================================================================================
3759
3760 void SMESH_Mesh_i::ExportMED(const char*    file,
3761                              CORBA::Boolean auto_groups,
3762                              CORBA::Long    version,
3763                              CORBA::Boolean overwrite,
3764                              CORBA::Boolean autoDimension)
3765 {
3766   //MESSAGE("MED minor version: "<< minor);
3767   SMESH_TRY;
3768   if ( _preMeshInfo )
3769     _preMeshInfo->FullLoadFromFile();
3770
3771   string aMeshName = prepareMeshNameAndGroups(file, overwrite);
3772   _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version, 0, autoDimension );
3773
3774   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportMED( r'"
3775                 << file << "', "
3776                 << "auto_groups=" <<auto_groups << ", "
3777                 << "version=" << version <<  ", "
3778                 << "overwrite=" << overwrite << ", "
3779                 << "meshPart=None, "
3780                 << "autoDimension=" << autoDimension << " )";
3781
3782   SMESH_CATCH( SMESH::throwCorbaException );
3783 }
3784
3785 CORBA::LongLong SMESH_Mesh_i::ExportMEDCoupling(CORBA::Boolean auto_groups, CORBA::Boolean autoDimension)
3786 {
3787   MEDCoupling::MCAuto<MEDCoupling::DataArrayByte> data;
3788   SMESH_TRY;
3789   // TODO : Fix me ! 2 next lines are required
3790   if( !this->_gen_i->isSSLMode() )
3791     SMESH::throwCorbaException("SMESH_Mesh_i::ExportMEDCoupling : only for embedded mode !");
3792   if ( _preMeshInfo )
3793     _preMeshInfo->FullLoadFromFile();
3794
3795   string aMeshName = this->generateMeshName();
3796   data = _impl->ExportMEDCoupling( aMeshName.c_str(), auto_groups, 0, autoDimension );
3797   SMESH_CATCH( SMESH::throwCorbaException );
3798   MEDCoupling::DataArrayByte *ret(data.retn());
3799   return reinterpret_cast<CORBA::LongLong>(ret);
3800 }
3801
3802 //================================================================================
3803 /*!
3804  * \brief Export a mesh to a DAT file
3805  */
3806 //================================================================================
3807
3808 void SMESH_Mesh_i::ExportDAT (const char *file, CORBA::Boolean renumber )
3809 {
3810   SMESH_TRY;
3811   if ( _preMeshInfo )
3812     _preMeshInfo->FullLoadFromFile();
3813
3814   // check names of groups
3815   checkGroupNames();
3816   // Update Python script
3817   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
3818                 << ".ExportDAT( r'" << file<< ", " << renumber << "' )";
3819
3820   // Perform Export
3821   PrepareForWriting( file );
3822   _impl->ExportDAT( file, /*part=*/nullptr, renumber );
3823
3824   SMESH_CATCH( SMESH::throwCorbaException );
3825 }
3826
3827 //================================================================================
3828 /*!
3829  * \brief Export a mesh to an UNV file
3830  */
3831 //================================================================================
3832
3833 void SMESH_Mesh_i::ExportUNV (const char *file, CORBA::Boolean renumber)
3834 {
3835   SMESH_TRY;
3836   if ( _preMeshInfo )
3837     _preMeshInfo->FullLoadFromFile();
3838
3839   // check names of groups
3840   checkGroupNames();
3841   // Update Python script
3842   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
3843                 << ".ExportUNV( r'" << file << "' " << renumber << "' )";
3844
3845   // Perform Export
3846   PrepareForWriting( file );
3847   _impl->ExportUNV( file, /*part=*/nullptr, renumber );
3848
3849   SMESH_CATCH( SMESH::throwCorbaException );
3850 }
3851
3852 //================================================================================
3853 /*!
3854  * \brief Export a mesh to an STL file
3855  */
3856 //================================================================================
3857
3858 void SMESH_Mesh_i::ExportSTL (const char *file, const bool isascii)
3859 {
3860   SMESH_TRY;
3861   if ( _preMeshInfo )
3862     _preMeshInfo->FullLoadFromFile();
3863
3864   // check names of groups
3865   checkGroupNames();
3866   // Update Python script
3867   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
3868                 << ".ExportSTL( r'" << file << "', " << isascii << " )";
3869
3870   CORBA::String_var name;
3871   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( _this() );
3872   if ( !so->_is_nil() )
3873     name = so->GetName();
3874
3875   // Perform Export
3876   PrepareForWriting( file );
3877   _impl->ExportSTL( file, isascii, name.in() );
3878
3879   SMESH_CATCH( SMESH::throwCorbaException );
3880 }
3881
3882 //================================================================================
3883
3884 class MEDFileSpeCls
3885 {
3886 public:
3887   MEDFileSpeCls(const char *   file,
3888                 CORBA::Boolean overwrite,
3889                 CORBA::Long    version)
3890     :_file(file), _overwrite(overwrite), _version(version)
3891   {}
3892   std::string prepareMeshNameAndGroups(SMESH_Mesh_i& self)
3893   {
3894     return self.prepareMeshNameAndGroups(_file.c_str(),_overwrite);
3895   }
3896
3897   void exportTo(SMESH_Mesh *mesh, const std::string& aMeshName, CORBA::Boolean auto_groups,
3898                 SMESH_MeshPartDS* partDS, CORBA::Boolean autoDimension, bool have0dField,
3899                 CORBA::Double ZTolerance, CORBA::Boolean saveNumbers )
3900   {
3901     mesh->ExportMED( _file.c_str(), aMeshName.c_str(), auto_groups, _version,
3902                      partDS, autoDimension, have0dField, ZTolerance, saveNumbers );
3903   }
3904
3905   void exportField(SMESH_Mesh_i& self, const std::string& aMeshName, bool have0dField,
3906                    SMESHDS_Mesh *meshDS, const GEOM::ListOfFields& fields,
3907                    const char*geomAssocFields)
3908   {
3909     DriverMED_W_Field fieldWriter;
3910     fieldWriter.SetFile( _file.c_str() );
3911     fieldWriter.SetMeshName( aMeshName );
3912     fieldWriter.AddODOnVertices( have0dField );
3913     self.exportMEDFields( fieldWriter, meshDS, fields, geomAssocFields );
3914   }
3915
3916   void prepareForWriting(SMESH_Mesh_i& self) { self.PrepareForWriting(_file.c_str(), _overwrite); }
3917
3918 private:
3919   std::string    _file;
3920   CORBA::Boolean _overwrite;
3921   CORBA::Long    _version;
3922 };
3923
3924 //================================================================================
3925 /*!
3926  * \brief Export a part of mesh to a med file
3927  */
3928 //================================================================================
3929
3930 template<class SPECLS>
3931 void SMESH_Mesh_i::ExportPartToMEDCommon(SPECLS&                   speCls,
3932                                          SMESH::SMESH_IDSource_ptr meshPart,
3933                                          CORBA::Boolean            auto_groups,
3934                                          CORBA::Boolean            autoDimension,
3935                                          const GEOM::ListOfFields& fields,
3936                                          const char*               geomAssocFields,
3937                                          CORBA::Double             ZTolerance,
3938                                          CORBA::Boolean            saveNumbers)
3939 {
3940   SMESH_TRY;
3941   if ( _preMeshInfo )
3942     _preMeshInfo->FullLoadFromFile();
3943
3944   // check fields
3945   bool have0dField = false;
3946   if ( fields.length() > 0 )
3947   {
3948     GEOM::GEOM_Object_var shapeToMesh = GetShapeToMesh();
3949     if ( shapeToMesh->_is_nil() )
3950       THROW_SALOME_CORBA_EXCEPTION( "No shape to mesh", SALOME::INTERNAL_ERROR );
3951
3952     for ( size_t i = 0; i < fields.length(); ++i )
3953     {
3954       if ( fields[i]->GetDataType() == GEOM::FDT_String )
3955         THROW_SALOME_CORBA_EXCEPTION
3956           ( "Export of string fields is not supported", SALOME::BAD_PARAM);
3957       GEOM::GEOM_Object_var fieldShape = fields[i]->GetShape();
3958       if ( fieldShape->_is_nil() )
3959         THROW_SALOME_CORBA_EXCEPTION( "Null shape under a field", SALOME::INTERNAL_ERROR );
3960       if ( !fieldShape->IsSame( shapeToMesh ) )
3961         THROW_SALOME_CORBA_EXCEPTION( "Field defined not on shape", SALOME::BAD_PARAM);
3962       if ( fields[i]->GetDimension() == 0 )
3963         have0dField = true;
3964     }
3965     if ( geomAssocFields )
3966       for ( int i = 0; geomAssocFields[i]; ++i )
3967         switch ( geomAssocFields[i] ) {
3968         case 'v':case 'e':case 'f':case 's': break;
3969         case 'V':case 'E':case 'F':case 'S': break;
3970         default: THROW_SALOME_CORBA_EXCEPTION
3971             ( "geomAssocFields can include only [vefs] characters", SALOME::BAD_PARAM);
3972         }
3973   }
3974
3975   SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
3976
3977   // write mesh
3978
3979   string aMeshName = "Mesh";
3980   SMESHUtils::Deleter< SMESH_MeshPartDS > tmpDSDeleter(0);
3981   if ( CORBA::is_nil( meshPart ) ||
3982        SMESH::DownCast< SMESH_Mesh_i* >( meshPart ))
3983   {
3984     aMeshName = speCls.prepareMeshNameAndGroups(*this);
3985     speCls.exportTo(_impl, aMeshName, auto_groups, nullptr, autoDimension,
3986                     have0dField, ZTolerance, saveNumbers );
3987     meshDS = _impl->GetMeshDS();
3988   }
3989   else
3990   {
3991     if ( _preMeshInfo )
3992       _preMeshInfo->FullLoadFromFile();
3993
3994     speCls.prepareForWriting(*this);
3995
3996     SALOMEDS::SObject_wrap SO = _gen_i->ObjectToSObject( meshPart );
3997     if ( !SO->_is_nil() ) {
3998       CORBA::String_var name = SO->GetName();
3999       aMeshName = name;
4000     }
4001
4002     SMESH_MeshPartDS* partDS = new SMESH_MeshPartDS( meshPart );
4003     speCls.exportTo(_impl, aMeshName, auto_groups, partDS, autoDimension,
4004                     have0dField, ZTolerance, saveNumbers);
4005     meshDS = tmpDSDeleter._obj = partDS;
4006   }
4007
4008   // write fields
4009
4010   if ( _impl->HasShapeToMesh() )
4011   {
4012     speCls.exportField( *this, aMeshName, have0dField, meshDS, fields, geomAssocFields);
4013   }
4014   SMESH_CATCH( SMESH::throwCorbaException );
4015 }
4016
4017 //================================================================================
4018 /*!
4019  * \brief Export a part of mesh to a med file
4020  */
4021 //================================================================================
4022
4023 void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
4024                                    const char*               file,
4025                                    CORBA::Boolean            auto_groups,
4026                                    CORBA::Long               version,
4027                                    CORBA::Boolean            overwrite,
4028                                    CORBA::Boolean            autoDimension,
4029                                    const GEOM::ListOfFields& fields,
4030                                    const char*               geomAssocFields,
4031                                    CORBA::Double             ZTolerance,
4032                                    CORBA::Boolean            saveNumbers)
4033 {
4034   MESSAGE("MED version: "<< version);
4035
4036   MEDFileSpeCls spe( file, overwrite, version );
4037   this->ExportPartToMEDCommon( spe, meshPart, auto_groups, autoDimension, fields,
4038                                geomAssocFields, ZTolerance, saveNumbers );
4039   // dump
4040   SMESH_TRY;
4041   GEOM::ListOfGBO_var goList = new GEOM::ListOfGBO;
4042   goList->length( fields.length() );
4043   for ( size_t i = 0; i < fields.length(); ++i )
4044   {
4045     GEOM::GEOM_BaseObject_var gbo = GEOM::GEOM_BaseObject::_narrow( fields[i] );
4046     goList[i] = gbo;
4047   }
4048   TPythonDump() << _this() << ".ExportPartToMED( "
4049                 << meshPart << ", r'"
4050                 << file << "', "
4051                 << auto_groups << ", "
4052                 << version << ", "
4053                 << overwrite << ", "
4054                 << autoDimension << ", "
4055                 << goList << ", '"
4056                 << ( geomAssocFields ? geomAssocFields : "" ) << "',"
4057                 << TVar( ZTolerance ) << ", "
4058                 << saveNumbers
4059                 << " )";
4060   SMESH_CATCH( SMESH::throwCorbaException );
4061 }
4062
4063 //================================================================================
4064
4065 class MEDFileMemSpeCls
4066 {
4067 public:
4068   std::string prepareMeshNameAndGroups(SMESH_Mesh_i& self) { return self.generateMeshName(); }
4069
4070   void exportTo(SMESH_Mesh *mesh, const std::string& aMeshName, CORBA::Boolean auto_groups,
4071                 SMESH_MeshPartDS* partDS, CORBA::Boolean autoDimension, bool have0dField,
4072                 CORBA::Double ZTolerance, CORBA::Boolean saveNumbers )
4073   {
4074     _res = mesh->ExportMEDCoupling(aMeshName.c_str(), auto_groups, partDS,
4075                                    autoDimension, have0dField, ZTolerance, saveNumbers );
4076   }
4077   void prepareForWriting(SMESH_Mesh_i& /*self*/) { /* nothing here */ }
4078
4079   void exportField(SMESH_Mesh_i& self, const std::string& aMeshName, bool have0dField,
4080                    SMESHDS_Mesh *meshDS, const GEOM::ListOfFields& fields,
4081                    const char*geomAssocFields)
4082   {
4083     DriverMED_W_Field_Mem fieldWriter(_res);
4084     fieldWriter.SetMeshName( aMeshName );
4085     fieldWriter.AddODOnVertices( have0dField );
4086     self.exportMEDFields( fieldWriter, meshDS, fields, geomAssocFields );
4087     _res = fieldWriter.getData();
4088   }
4089 public:
4090   MEDCoupling::MCAuto<MEDCoupling::DataArrayByte> getData() { return _res; }
4091
4092 private:
4093   MEDCoupling::MCAuto<MEDCoupling::DataArrayByte> _res;
4094 };
4095
4096 //================================================================================
4097 /*!
4098  * \brief Export a part of mesh to a MEDCoupling DS
4099  */
4100 //================================================================================
4101
4102 CORBA::LongLong SMESH_Mesh_i::ExportPartToMEDCoupling(SMESH::SMESH_IDSource_ptr meshPart,
4103                                                       CORBA::Boolean            auto_groups,
4104                                                       CORBA::Boolean            autoDimension,
4105                                                       const GEOM::ListOfFields& fields,
4106                                                       const char*               geomAssocFields,
4107                                                       CORBA::Double             ZTolerance,
4108                                                       CORBA::Boolean            saveNumbers)
4109 {
4110   MEDCoupling::MCAuto<MEDCoupling::DataArrayByte> data;
4111
4112   SMESH_TRY;
4113   if( !this->_gen_i->isSSLMode() )
4114     SMESH::throwCorbaException("SMESH_Mesh_i::ExportPartToMEDCoupling : only for embedded mode !");
4115
4116   MEDFileMemSpeCls spe;
4117   this->ExportPartToMEDCommon( spe, meshPart, auto_groups, autoDimension, fields, geomAssocFields,
4118                                ZTolerance, saveNumbers );
4119   data = spe.getData();
4120
4121   SMESH_CATCH( SMESH::throwCorbaException );
4122
4123   MEDCoupling::DataArrayByte *ret(data.retn());
4124   return reinterpret_cast<CORBA::LongLong>(ret);
4125 }
4126
4127 //================================================================================
4128 /*!
4129  * Write GEOM fields to MED file
4130  */
4131 //================================================================================
4132
4133 void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
4134                                     SMESHDS_Mesh*             meshDS,
4135                                     const GEOM::ListOfFields& fields,
4136                                     const char*               geomAssocFields)
4137 {
4138 #define METH "SMESH_Mesh_i::exportMEDFields() "
4139
4140   if (( fields.length() < 1 ) &&
4141       ( !geomAssocFields || !geomAssocFields[0] ))
4142     return;
4143
4144   std::vector< std::vector< double > > dblVals;
4145   std::vector< std::vector< int > >    intVals;
4146   std::vector< int >                   subIdsByDim[ 4 ];
4147   const double noneDblValue = 0.;
4148   const double noneIntValue = 0;
4149
4150   for ( size_t iF = 0; iF < fields.length(); ++iF )
4151   {
4152     // set field data
4153
4154     int dim = fields[ iF ]->GetDimension();
4155     SMDSAbs_ElementType elemType;
4156     TopAbs_ShapeEnum    shapeType;
4157     switch ( dim ) {
4158     case 0: elemType = SMDSAbs_0DElement; shapeType = TopAbs_VERTEX; break;
4159     case 1: elemType = SMDSAbs_Edge;      shapeType = TopAbs_EDGE;   break;
4160     case 2: elemType = SMDSAbs_Face;      shapeType = TopAbs_FACE;   break;
4161     case 3: elemType = SMDSAbs_Volume;    shapeType = TopAbs_SOLID;  break;
4162     default:
4163       continue; // skip fields on whole shape
4164     }
4165     GEOM::field_data_type dataType = fields[ iF ]->GetDataType();
4166     if ( dataType == GEOM::FDT_String )
4167       continue;
4168     GEOM::ListOfLong_var stepIDs = fields[ iF ]->GetSteps();
4169     if ( stepIDs->length() < 1 )
4170       continue;
4171     GEOM::string_array_var comps = fields[ iF ]->GetComponents();
4172     if ( comps->length() < 1 )
4173       continue;
4174     CORBA::String_var       name = fields[ iF ]->GetName();
4175
4176     if ( !fieldWriter.Set( meshDS,
4177                            name.in(),
4178                            elemType,
4179                            comps->length(),
4180                            /*isIntData=*/false ))//( dataType == GEOM::FDT_Int )))
4181       continue;
4182
4183     for ( size_t iC = 0; iC < comps->length(); ++iC )
4184       fieldWriter.SetCompName( iC, comps[ iC ].in() );
4185
4186     dblVals.resize( comps->length() );
4187     intVals.resize( comps->length() );
4188
4189     // find sub-shape IDs
4190
4191     std::vector< int >& subIds = subIdsByDim[ dim ];
4192     if ( subIds.empty() )
4193       for ( int id = 1; id <= meshDS->MaxShapeIndex(); ++id )
4194         if ( meshDS->IndexToShape( id ).ShapeType() == shapeType )
4195           subIds.push_back( id );
4196
4197     // write steps
4198
4199     SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
4200     if ( !elemIt )
4201       continue;
4202
4203     for ( size_t iS = 0; iS < stepIDs->length(); ++iS )
4204     {
4205       GEOM::GEOM_FieldStep_var step = fields[ iF ]->GetStep( stepIDs[ iS ]);
4206       if ( step->_is_nil() )
4207         continue;
4208
4209       CORBA::Long stamp = step->GetStamp();
4210       CORBA::Long id    = step->GetID();
4211       fieldWriter.SetDtIt( int( stamp ), int( id ));
4212
4213       // fill dblVals or intVals
4214       for ( size_t iC = 0; iC < comps->length(); ++iC )
4215         if ( dataType == GEOM::FDT_Double )
4216         {
4217           dblVals[ iC ].clear();
4218           dblVals[ iC ].resize( meshDS->MaxShapeIndex()+1, 0 );
4219         }
4220         else
4221         {
4222           intVals[ iC ].clear();
4223           intVals[ iC ].resize( meshDS->MaxShapeIndex()+1, 0 );
4224         }
4225       switch ( dataType )
4226       {
4227       case GEOM::FDT_Double:
4228       {
4229         GEOM::GEOM_DoubleFieldStep_var dblStep = GEOM::GEOM_DoubleFieldStep::_narrow( step );
4230         if ( dblStep->_is_nil() ) continue;
4231         GEOM::ListOfDouble_var vv = dblStep->GetValues();
4232         if ( vv->length() != subIds.size() * comps->length() )
4233           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
4234         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
4235           for ( size_t iC = 0; iC < comps->length(); ++iC )
4236             dblVals[ iC ][ subIds[ iS ]] = vv[ iV++ ];
4237         break;
4238       }
4239       case GEOM::FDT_Int:
4240       {
4241         GEOM::GEOM_IntFieldStep_var intStep = GEOM::GEOM_IntFieldStep::_narrow( step );
4242         if ( intStep->_is_nil() ) continue;
4243         GEOM::ListOfLong_var vv = intStep->GetValues();
4244         if ( vv->length() != subIds.size() * comps->length() )
4245           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
4246         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
4247           for ( size_t iC = 0; iC < comps->length(); ++iC )
4248             intVals[ iC ][ subIds[ iS ]] = (int) vv[ iV++ ];
4249         break;
4250       }
4251       case GEOM::FDT_Bool:
4252       {
4253         GEOM::GEOM_BoolFieldStep_var boolStep = GEOM::GEOM_BoolFieldStep::_narrow( step );
4254         if ( boolStep->_is_nil() ) continue;
4255         GEOM::short_array_var vv = boolStep->GetValues();
4256         if ( vv->length() != subIds.size() * comps->length() )
4257           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
4258         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
4259           for ( size_t iC = 0; iC < comps->length(); ++iC )
4260             intVals[ iC ][ subIds[ iS ]] = (int) vv[ iV++ ];
4261         break;
4262       }
4263       default: continue;
4264       }
4265
4266       // pass values to fieldWriter
4267       elemIt = fieldWriter.GetOrderedElems();
4268       if ( dataType == GEOM::FDT_Double )
4269         while ( elemIt->more() )
4270         {
4271           const SMDS_MeshElement* e = elemIt->next();
4272           const int shapeID = e->getshapeId();
4273           if ( shapeID < 1 || shapeID >= (int) dblVals[0].size() )
4274             for ( size_t iC = 0; iC < comps->length(); ++iC )
4275               fieldWriter.AddValue( noneDblValue );
4276           else
4277             for ( size_t iC = 0; iC < comps->length(); ++iC )
4278               fieldWriter.AddValue( dblVals[ iC ][ shapeID ]);
4279         }
4280       else
4281         while ( elemIt->more() )
4282         {
4283           const SMDS_MeshElement* e = elemIt->next();
4284           const int shapeID = e->getshapeId();
4285           if ( shapeID < 1 || shapeID >= (int) intVals[0].size() )
4286             for ( size_t iC = 0; iC < comps->length(); ++iC )
4287               fieldWriter.AddValue( (double) noneIntValue );
4288           else
4289             for ( size_t iC = 0; iC < comps->length(); ++iC )
4290               fieldWriter.AddValue( (double) intVals[ iC ][ shapeID ]);
4291         }
4292
4293       // write a step
4294       fieldWriter.Perform();
4295       SMESH_ComputeErrorPtr res = fieldWriter.GetError();
4296       if ( res && res->IsKO() )
4297       {
4298         if ( res->myComment.empty() )
4299         { THROW_SALOME_CORBA_EXCEPTION( METH "Fatal error", SALOME::INTERNAL_ERROR ); }
4300         else
4301         { THROW_SALOME_CORBA_EXCEPTION( res->myComment.c_str(), SALOME::INTERNAL_ERROR ); }
4302       }
4303
4304     } // loop on steps
4305   } // loop on fields
4306
4307   if ( !geomAssocFields || !geomAssocFields[0] )
4308     return;
4309
4310   // write geomAssocFields
4311
4312   std::vector< int > shapeDim( TopAbs_SHAPE + 1 );
4313   shapeDim[ TopAbs_COMPOUND  ] = 3;
4314   shapeDim[ TopAbs_COMPSOLID ] = 3;
4315   shapeDim[ TopAbs_SOLID     ] = 3;
4316   shapeDim[ TopAbs_SHELL     ] = 2;
4317   shapeDim[ TopAbs_FACE      ] = 2;
4318   shapeDim[ TopAbs_WIRE      ] = 1;
4319   shapeDim[ TopAbs_EDGE      ] = 1;
4320   shapeDim[ TopAbs_VERTEX    ] = 0;
4321   shapeDim[ TopAbs_SHAPE     ] = 3;
4322
4323   for ( int iF = 0; geomAssocFields[ iF ]; ++iF )
4324   {
4325     std::vector< std::string > compNames;
4326     switch ( geomAssocFields[ iF ]) {
4327     case 'v': case 'V':
4328       fieldWriter.Set( meshDS, "_vertices_", SMDSAbs_Node, /*nbComps=*/2, /*isInt=*/false );
4329       compNames.push_back( "dim" );
4330       break;
4331     case 'e': case 'E':
4332       fieldWriter.Set( meshDS, "_edges_", SMDSAbs_Edge, /*nbComps=*/1, /*isInt=*/false );
4333       break;
4334     case 'f': case 'F':
4335       fieldWriter.Set( meshDS, "_faces_", SMDSAbs_Face, /*nbComps=*/1, /*isInt=*/false );
4336       break;
4337     case 's': case 'S':
4338       fieldWriter.Set( meshDS, "_solids_", SMDSAbs_Volume, /*nbComps=*/1, /*isInt=*/false );
4339       break;
4340     default: continue;
4341     }
4342     compNames.push_back( "id" );
4343     for ( size_t iC = 0; iC < compNames.size(); ++iC )
4344       fieldWriter.SetCompName( iC, compNames[ iC ].c_str() );
4345
4346     fieldWriter.SetDtIt( -1, -1 );
4347
4348     SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
4349     if ( !elemIt )
4350       continue;
4351
4352     if ( compNames.size() == 2 ) // _vertices_
4353       while ( elemIt->more() )
4354       {
4355         const SMDS_MeshElement* e = elemIt->next();
4356         const int shapeID = e->getshapeId();
4357         if ( shapeID < 1 )
4358         {
4359           fieldWriter.AddValue( (double) -1 );
4360           fieldWriter.AddValue( (double) -1 );
4361         }
4362         else
4363         {
4364           const TopoDS_Shape& S = meshDS->IndexToShape( shapeID );
4365           fieldWriter.AddValue( (double) ( S.IsNull() ? -1 : shapeDim[ S.ShapeType() ]));
4366           fieldWriter.AddValue( (double) shapeID );
4367         }
4368       }
4369     else
4370       while ( elemIt->more() )
4371       {
4372         const SMDS_MeshElement* e = elemIt->next();
4373         const int shapeID = e->getshapeId();
4374         if ( shapeID < 1 )
4375           fieldWriter.AddValue( (double) -1 );
4376         else
4377           fieldWriter.AddValue( (double) shapeID );
4378       }
4379
4380     // write a step
4381     fieldWriter.Perform();
4382     SMESH_ComputeErrorPtr res = fieldWriter.GetError();
4383     if ( res && res->IsKO() )
4384     {
4385       if ( res->myComment.empty() )
4386       { THROW_SALOME_CORBA_EXCEPTION( METH "Fatal error", SALOME::INTERNAL_ERROR ); }
4387       else
4388       { THROW_SALOME_CORBA_EXCEPTION( res->myComment.c_str(), SALOME::INTERNAL_ERROR ); }
4389     }
4390
4391   } // loop on geomAssocFields
4392
4393 #undef METH
4394 }
4395
4396 //================================================================================
4397 /*!
4398  * \brief Export a part of mesh to a DAT file
4399  */
4400 //================================================================================
4401
4402 void SMESH_Mesh_i::ExportPartToDAT(SMESH::SMESH_IDSource_ptr meshPart,
4403                                    const char*               file,
4404                                    CORBA::Boolean            renumber )
4405 {
4406   SMESH_TRY;
4407
4408   SMESH_MeshPartDS partDS( meshPart );
4409   _impl->ExportDAT( file, &partDS, renumber );
4410
4411   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
4412                 << ".ExportPartToDAT( " << meshPart << ", r'" << file << ", " << renumber << "' )";
4413
4414   SMESH_CATCH( SMESH::throwCorbaException );
4415 }
4416 //================================================================================
4417 /*!
4418  * \brief Export a part of mesh to an UNV file
4419  */
4420 //================================================================================
4421
4422 void SMESH_Mesh_i::ExportPartToUNV(SMESH::SMESH_IDSource_ptr meshPart,
4423                                    const char*               file,
4424                                    CORBA::Boolean            renumber)
4425 {
4426   SMESH_TRY;
4427   if ( _preMeshInfo )
4428     _preMeshInfo->FullLoadFromFile();
4429
4430   PrepareForWriting(file);
4431
4432   SMESH_MeshPartDS partDS( meshPart );
4433   _impl->ExportUNV(file, &partDS, renumber );
4434
4435   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
4436                 << ".ExportPartToUNV( " << meshPart<< ", r'" << file << ", " << renumber << "' )";
4437
4438   SMESH_CATCH( SMESH::throwCorbaException );
4439 }
4440 //================================================================================
4441 /*!
4442  * \brief Export a part of mesh to an STL file
4443  */
4444 //================================================================================
4445
4446 void SMESH_Mesh_i::ExportPartToSTL(::SMESH::SMESH_IDSource_ptr meshPart,
4447                                    const char*                 file,
4448                                    ::CORBA::Boolean            isascii)
4449 {
4450   SMESH_TRY;
4451   if ( _preMeshInfo )
4452     _preMeshInfo->FullLoadFromFile();
4453
4454   PrepareForWriting(file);
4455
4456   CORBA::String_var name;
4457   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( meshPart );
4458   if ( !so->_is_nil() )
4459     name = so->GetName();
4460
4461   SMESH_MeshPartDS partDS( meshPart );
4462   _impl->ExportSTL( file, isascii, name.in(), &partDS );
4463
4464   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportPartToSTL( "
4465                 << meshPart<< ", r'" << file << "', " << isascii << ")";
4466
4467   SMESH_CATCH( SMESH::throwCorbaException );
4468 }
4469
4470 //================================================================================
4471 /*!
4472  * \brief Export a part of mesh to an STL file
4473  */
4474 //================================================================================
4475
4476 void SMESH_Mesh_i::ExportCGNS(::SMESH::SMESH_IDSource_ptr meshPart,
4477                               const char*                 file,
4478                               CORBA::Boolean              overwrite,
4479                               CORBA::Boolean              groupElemsByType)
4480 {
4481 #ifdef WITH_CGNS
4482   SMESH_TRY;
4483   if ( _preMeshInfo )
4484     _preMeshInfo->FullLoadFromFile();
4485
4486   PrepareForWriting(file,overwrite);
4487
4488   std::string meshName("");
4489   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( meshPart );
4490   if ( !so->_is_nil() )
4491   {
4492     CORBA::String_var name = so->GetName();
4493     meshName = name.in();
4494   }
4495   SMESH_TRY;
4496
4497   SMESH_MeshPartDS partDS( meshPart );
4498   _impl->ExportCGNS(file, &partDS, meshName.c_str(), groupElemsByType );
4499
4500   SMESH_CATCH( SMESH::throwCorbaException );
4501
4502   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportCGNS( "
4503                 << meshPart<< ", r'" << file << "', " << overwrite << ")";
4504
4505   SMESH_CATCH( SMESH::throwCorbaException );
4506
4507 #else
4508   THROW_SALOME_CORBA_EXCEPTION("CGNS library is unavailable", SALOME::INTERNAL_ERROR);
4509 #endif
4510 }
4511
4512 //================================================================================
4513 /*!
4514  * \brief Export a part of mesh to a GMF file
4515  */
4516 //================================================================================
4517
4518 void SMESH_Mesh_i::ExportGMF(::SMESH::SMESH_IDSource_ptr meshPart,
4519                              const char*                 file,
4520                              bool                        withRequiredGroups)
4521 {
4522   SMESH_TRY;
4523   if ( _preMeshInfo )
4524     _preMeshInfo->FullLoadFromFile();
4525
4526   PrepareForWriting(file,/*overwrite=*/true);
4527
4528   SMESH_MeshPartDS partDS( meshPart );
4529   _impl->ExportGMF(file, &partDS, withRequiredGroups);
4530
4531   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportGMF( "
4532                 << meshPart<< ", r'"
4533                 << file << "', "
4534                 << withRequiredGroups << ")";
4535
4536   SMESH_CATCH( SMESH::throwCorbaException );
4537 }
4538
4539 //=============================================================================
4540 /*!
4541  * Return computation progress [0.,1]
4542  */
4543 //=============================================================================
4544
4545 CORBA::Double SMESH_Mesh_i::GetComputeProgress()
4546 {
4547   SMESH_TRY;
4548
4549   return _impl->GetComputeProgress();
4550
4551   SMESH_CATCH( SMESH::doNothing );
4552   return 0.;
4553 }
4554
4555 //================================================================================
4556 /*!
4557  * \brief Return nb of nodes
4558  */
4559 //================================================================================
4560
4561 SMESH::smIdType SMESH_Mesh_i::NbNodes()
4562 {
4563   Unexpect aCatch(SALOME_SalomeException);
4564   if ( _preMeshInfo )
4565     return _preMeshInfo->NbNodes();
4566
4567   return _impl->NbNodes();
4568 }
4569
4570 //================================================================================
4571 /*!
4572  * \brief Return nb of elements
4573  */
4574 //================================================================================
4575
4576 SMESH::smIdType SMESH_Mesh_i::NbElements()
4577 {
4578   Unexpect aCatch(SALOME_SalomeException);
4579   if ( _preMeshInfo )
4580     return _preMeshInfo->NbElements();
4581
4582   return Nb0DElements() + NbEdges() + NbFaces() + NbVolumes() + NbBalls();
4583 }
4584
4585 //================================================================================
4586 /*!
4587  * \brief Return nb of 0D elements
4588  */
4589 //================================================================================
4590
4591 SMESH::smIdType SMESH_Mesh_i::Nb0DElements()
4592 {
4593   Unexpect aCatch(SALOME_SalomeException);
4594   if ( _preMeshInfo )
4595     return _preMeshInfo->Nb0DElements();
4596
4597   return _impl->Nb0DElements();
4598 }
4599
4600 //================================================================================
4601 /*!
4602  * \brief Return nb of BALL elements
4603  */
4604 //================================================================================
4605
4606 SMESH::smIdType SMESH_Mesh_i::NbBalls()
4607 {
4608   Unexpect aCatch(SALOME_SalomeException);
4609   if ( _preMeshInfo )
4610     return _preMeshInfo->NbBalls();
4611
4612   return _impl->NbBalls();
4613 }
4614
4615 //================================================================================
4616 /*!
4617  * \brief Return nb of 1D elements
4618  */
4619 //================================================================================
4620
4621 SMESH::smIdType SMESH_Mesh_i::NbEdges()
4622 {
4623   Unexpect aCatch(SALOME_SalomeException);
4624   if ( _preMeshInfo )
4625     return _preMeshInfo->NbEdges();
4626
4627   return _impl->NbEdges();
4628 }
4629
4630 //================================================================================
4631 /*!
4632  * \brief Return nb of edges
4633  */
4634 //================================================================================
4635
4636 SMESH::smIdType SMESH_Mesh_i::NbEdgesOfOrder(SMESH::ElementOrder order)
4637 {
4638   Unexpect aCatch(SALOME_SalomeException);
4639   if ( _preMeshInfo )
4640     return _preMeshInfo->NbEdges( (SMDSAbs_ElementOrder) order );
4641
4642   return _impl->NbEdges( (SMDSAbs_ElementOrder) order);
4643 }
4644
4645 //================================================================================
4646 /*!
4647  * \brief Return nb of faces
4648  */
4649 //================================================================================
4650
4651 SMESH::smIdType SMESH_Mesh_i::NbFaces()
4652 {
4653   Unexpect aCatch(SALOME_SalomeException);
4654   if ( _preMeshInfo )
4655     return _preMeshInfo->NbFaces();
4656
4657   return _impl->NbFaces();
4658 }
4659
4660 //================================================================================
4661 /*!
4662  * \brief Return nb of tringles
4663  */
4664 //================================================================================
4665
4666 SMESH::smIdType SMESH_Mesh_i::NbTriangles()
4667 {
4668   Unexpect aCatch(SALOME_SalomeException);
4669   if ( _preMeshInfo )
4670     return _preMeshInfo->NbTriangles();
4671
4672   return _impl->NbTriangles();
4673 }
4674
4675 //================================================================================
4676 /*!
4677  * \brief Return nb of bi-quadratic triangles
4678  */
4679 //================================================================================
4680
4681 SMESH::smIdType SMESH_Mesh_i::NbBiQuadTriangles()
4682 {
4683   Unexpect aCatch(SALOME_SalomeException);
4684   if ( _preMeshInfo )
4685     return _preMeshInfo->NbBiQuadTriangles();
4686
4687   return _impl->NbBiQuadTriangles();
4688 }
4689
4690 SMESH::smIdType SMESH_Mesh_i::NbQuadrangles()
4691 {
4692   Unexpect aCatch(SALOME_SalomeException);
4693   if ( _preMeshInfo )
4694     return _preMeshInfo->NbQuadrangles();
4695
4696   return _impl->NbQuadrangles();
4697 }
4698
4699 SMESH::smIdType SMESH_Mesh_i::NbBiQuadQuadrangles()
4700 {
4701   Unexpect aCatch(SALOME_SalomeException);
4702   if ( _preMeshInfo )
4703     return _preMeshInfo->NbBiQuadQuadrangles();
4704
4705   return _impl->NbBiQuadQuadrangles();
4706 }
4707
4708 SMESH::smIdType SMESH_Mesh_i::NbPolygons()
4709 {
4710   Unexpect aCatch(SALOME_SalomeException);
4711   if ( _preMeshInfo )
4712     return _preMeshInfo->NbPolygons();
4713
4714   return _impl->NbPolygons();
4715 }
4716
4717 SMESH::smIdType SMESH_Mesh_i::NbPolygonsOfOrder(SMESH::ElementOrder order)
4718 {
4719   Unexpect aCatch(SALOME_SalomeException);
4720   if ( _preMeshInfo )
4721     return _preMeshInfo->NbPolygons((SMDSAbs_ElementOrder) order);
4722
4723   return _impl->NbPolygons((SMDSAbs_ElementOrder)order);
4724 }
4725
4726 SMESH::smIdType SMESH_Mesh_i::NbFacesOfOrder(SMESH::ElementOrder order)
4727 {
4728   Unexpect aCatch(SALOME_SalomeException);
4729   if ( _preMeshInfo )
4730     return _preMeshInfo->NbFaces( (SMDSAbs_ElementOrder) order );
4731
4732   return _impl->NbFaces( (SMDSAbs_ElementOrder) order);
4733 }
4734
4735 SMESH::smIdType SMESH_Mesh_i::NbTrianglesOfOrder(SMESH::ElementOrder order)
4736 {
4737   Unexpect aCatch(SALOME_SalomeException);
4738   if ( _preMeshInfo )
4739     return _preMeshInfo->NbTriangles( (SMDSAbs_ElementOrder) order );
4740
4741   return _impl->NbTriangles( (SMDSAbs_ElementOrder) order);
4742 }
4743
4744 SMESH::smIdType SMESH_Mesh_i::NbQuadranglesOfOrder(SMESH::ElementOrder order)
4745 {
4746   Unexpect aCatch(SALOME_SalomeException);
4747   if ( _preMeshInfo )
4748     return _preMeshInfo->NbQuadrangles( (SMDSAbs_ElementOrder) order );
4749
4750   return _impl->NbQuadrangles( (SMDSAbs_ElementOrder) order);
4751 }
4752
4753 //=============================================================================
4754
4755 SMESH::smIdType SMESH_Mesh_i::NbVolumes()
4756 {
4757   Unexpect aCatch(SALOME_SalomeException);
4758   if ( _preMeshInfo )
4759     return _preMeshInfo->NbVolumes();
4760
4761   return _impl->NbVolumes();
4762 }
4763
4764 SMESH::smIdType SMESH_Mesh_i::NbTetras()
4765 {
4766   Unexpect aCatch(SALOME_SalomeException);
4767   if ( _preMeshInfo )
4768     return _preMeshInfo->NbTetras();
4769
4770   return _impl->NbTetras();
4771 }
4772
4773 SMESH::smIdType SMESH_Mesh_i::NbHexas()
4774 {
4775   Unexpect aCatch(SALOME_SalomeException);
4776   if ( _preMeshInfo )
4777     return _preMeshInfo->NbHexas();
4778
4779   return _impl->NbHexas();
4780 }
4781
4782 SMESH::smIdType SMESH_Mesh_i::NbTriQuadraticHexas()
4783 {
4784   Unexpect aCatch(SALOME_SalomeException);
4785   if ( _preMeshInfo )
4786     return _preMeshInfo->NbTriQuadHexas();
4787
4788   return _impl->NbTriQuadraticHexas();
4789 }
4790
4791 SMESH::smIdType SMESH_Mesh_i::NbPyramids()
4792 {
4793   Unexpect aCatch(SALOME_SalomeException);
4794   if ( _preMeshInfo )
4795     return _preMeshInfo->NbPyramids();
4796
4797   return _impl->NbPyramids();
4798 }
4799
4800 SMESH::smIdType SMESH_Mesh_i::NbPrisms()
4801 {
4802   Unexpect aCatch(SALOME_SalomeException);
4803   if ( _preMeshInfo )
4804     return _preMeshInfo->NbPrisms();
4805
4806   return _impl->NbPrisms();
4807 }
4808
4809 SMESH::smIdType SMESH_Mesh_i::NbHexagonalPrisms()
4810 {
4811   Unexpect aCatch(SALOME_SalomeException);
4812   if ( _preMeshInfo )
4813     return _preMeshInfo->NbHexPrisms();
4814
4815   return _impl->NbHexagonalPrisms();
4816 }
4817
4818 SMESH::smIdType SMESH_Mesh_i::NbPolyhedrons()
4819 {
4820   Unexpect aCatch(SALOME_SalomeException);
4821   if ( _preMeshInfo )
4822     return _preMeshInfo->NbPolyhedrons();
4823
4824   return _impl->NbPolyhedrons();
4825 }
4826
4827 SMESH::smIdType SMESH_Mesh_i::NbVolumesOfOrder(SMESH::ElementOrder order)
4828 {
4829   Unexpect aCatch(SALOME_SalomeException);
4830   if ( _preMeshInfo )
4831     return _preMeshInfo->NbVolumes( (SMDSAbs_ElementOrder) order );
4832
4833   return _impl->NbVolumes( (SMDSAbs_ElementOrder) order);
4834 }
4835
4836 SMESH::smIdType SMESH_Mesh_i::NbTetrasOfOrder(SMESH::ElementOrder order)
4837 {
4838   Unexpect aCatch(SALOME_SalomeException);
4839   if ( _preMeshInfo )
4840     return _preMeshInfo->NbTetras( (SMDSAbs_ElementOrder) order);
4841
4842   return _impl->NbTetras( (SMDSAbs_ElementOrder) order);
4843 }
4844
4845 SMESH::smIdType SMESH_Mesh_i::NbHexasOfOrder(SMESH::ElementOrder order)
4846 {
4847   Unexpect aCatch(SALOME_SalomeException);
4848   if ( _preMeshInfo )
4849     return _preMeshInfo->NbHexas( (SMDSAbs_ElementOrder) order);
4850
4851   return _impl->NbHexas( (SMDSAbs_ElementOrder) order);
4852 }
4853
4854 SMESH::smIdType SMESH_Mesh_i::NbPyramidsOfOrder(SMESH::ElementOrder order)
4855 {
4856   Unexpect aCatch(SALOME_SalomeException);
4857   if ( _preMeshInfo )
4858     return _preMeshInfo->NbPyramids( (SMDSAbs_ElementOrder) order);
4859
4860   return _impl->NbPyramids( (SMDSAbs_ElementOrder) order);
4861 }
4862
4863 SMESH::smIdType SMESH_Mesh_i::NbPrismsOfOrder(SMESH::ElementOrder order)
4864 {
4865   Unexpect aCatch(SALOME_SalomeException);
4866   if ( _preMeshInfo )
4867     return _preMeshInfo->NbPrisms( (SMDSAbs_ElementOrder) order);
4868
4869   return _impl->NbPrisms( (SMDSAbs_ElementOrder) order);
4870 }
4871
4872 //=============================================================================
4873 /*!
4874  * Return nb of published sub-meshes
4875  */
4876 //=============================================================================
4877
4878 SMESH::smIdType SMESH_Mesh_i::NbSubMesh()
4879 {
4880   Unexpect aCatch(SALOME_SalomeException);
4881   return _mapSubMesh_i.size();
4882 }
4883
4884 //=============================================================================
4885 /*!
4886  * Dumps mesh into a string
4887  */
4888 //=============================================================================
4889
4890 char* SMESH_Mesh_i::Dump()
4891 {
4892   ostringstream os;
4893   _impl->Dump( os );
4894   return CORBA::string_dup( os.str().c_str() );
4895 }
4896
4897 //=============================================================================
4898 /*!
4899  * Method of SMESH_IDSource interface
4900  */
4901 //=============================================================================
4902
4903 SMESH::smIdType_array* SMESH_Mesh_i::GetIDs()
4904 {
4905   return GetElementsId();
4906 }
4907
4908 //=============================================================================
4909 /*!
4910  * Return ids of all elements
4911  */
4912 //=============================================================================
4913
4914 SMESH::smIdType_array* SMESH_Mesh_i::GetElementsId()
4915 {
4916   Unexpect aCatch(SALOME_SalomeException);
4917   if ( _preMeshInfo )
4918     _preMeshInfo->FullLoadFromFile();
4919
4920   SMESH::smIdType_array_var aResult = new SMESH::smIdType_array();
4921   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
4922
4923   if ( aSMESHDS_Mesh == NULL )
4924     return aResult._retn();
4925
4926   smIdType nbElements = NbElements();
4927   aResult->length( nbElements );
4928   SMDS_ElemIteratorPtr anIt = aSMESHDS_Mesh->elementsIterator();
4929   for ( smIdType i = 0, n = nbElements; i < n && anIt->more(); i++ )
4930     aResult[i] = anIt->next()->GetID();
4931
4932   return aResult._retn();
4933 }
4934
4935
4936 //=============================================================================
4937 /*!
4938  * Return ids of all elements of given type
4939  */
4940 //=============================================================================
4941
4942 SMESH::smIdType_array* SMESH_Mesh_i::GetElementsByType( SMESH::ElementType theElemType )
4943 {
4944   Unexpect aCatch(SALOME_SalomeException);
4945   if ( _preMeshInfo )
4946     _preMeshInfo->FullLoadFromFile();
4947
4948   SMESH::smIdType_array_var aResult = new SMESH::smIdType_array();
4949   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
4950
4951   if ( aSMESHDS_Mesh == NULL )
4952     return aResult._retn();
4953
4954   smIdType nbElements = NbElements();
4955
4956   // No sense in returning ids of elements along with ids of nodes:
4957   // when theElemType == SMESH::ALL, return node ids only if
4958   // there are no elements
4959   if ( theElemType == SMESH::NODE || (theElemType == SMESH::ALL && nbElements == 0) )
4960     return GetNodesId();
4961
4962   aResult->length( nbElements );
4963
4964   smIdType i = 0;
4965
4966   SMDS_ElemIteratorPtr anIt = aSMESHDS_Mesh->elementsIterator( (SMDSAbs_ElementType)theElemType );
4967   while ( i < nbElements && anIt->more() )
4968     aResult[i++] = anIt->next()->GetID();
4969
4970   aResult->length( i );
4971
4972   return aResult._retn();
4973 }
4974
4975 //=============================================================================
4976 /*!
4977  * Return ids of all nodes
4978  */
4979 //=============================================================================
4980
4981 SMESH::smIdType_array* SMESH_Mesh_i::GetNodesId()
4982 {
4983   Unexpect aCatch(SALOME_SalomeException);
4984   if ( _preMeshInfo )
4985     _preMeshInfo->FullLoadFromFile();
4986
4987   SMESH::smIdType_array_var aResult = new SMESH::smIdType_array();
4988   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4989
4990   if ( aMeshDS == NULL )
4991     return aResult._retn();
4992
4993   smIdType nbNodes = NbNodes();
4994   aResult->length( nbNodes );
4995   SMDS_NodeIteratorPtr anIt = aMeshDS->nodesIterator();
4996   for ( smIdType i = 0, n = nbNodes; i < n && anIt->more(); i++ )
4997     aResult[i] = anIt->next()->GetID();
4998
4999   return aResult._retn();
5000 }
5001
5002 //=============================================================================
5003 /*!
5004  * Return type of the given element
5005  */
5006 //=============================================================================
5007
5008 SMESH::ElementType SMESH_Mesh_i::GetElementType( const SMESH::smIdType id, const bool iselem )
5009 {
5010   SMESH::ElementType type = SMESH::ALL;
5011   SMESH_TRY;
5012
5013   if ( _preMeshInfo )
5014     _preMeshInfo->FullLoadFromFile();
5015
5016   type = ( SMESH::ElementType ) _impl->GetElementType( id, iselem );
5017
5018   SMESH_CATCH( SMESH::throwCorbaException );
5019
5020   return type;
5021 }
5022
5023 //=============================================================================
5024 /*!
5025  * Return geometric type of the given element
5026  */
5027 //=============================================================================
5028
5029 SMESH::EntityType SMESH_Mesh_i::GetElementGeomType( const SMESH::smIdType id )
5030 {
5031   if ( _preMeshInfo )
5032     _preMeshInfo->FullLoadFromFile();
5033
5034   const SMDS_MeshElement* e = _impl->GetMeshDS()->FindElement(id);
5035   if ( !e )
5036     THROW_SALOME_CORBA_EXCEPTION( "invalid element id", SALOME::BAD_PARAM );
5037
5038   return ( SMESH::EntityType ) e->GetEntityType();
5039 }
5040
5041 //=============================================================================
5042 /*!
5043  * Return type of the given element
5044  */
5045 //=============================================================================
5046
5047 SMESH::GeometryType SMESH_Mesh_i::GetElementShape( const SMESH::smIdType id )
5048 {
5049   if ( _preMeshInfo )
5050     _preMeshInfo->FullLoadFromFile();
5051
5052   const SMDS_MeshElement* e = _impl->GetMeshDS()->FindElement(id);
5053   if ( !e )
5054     THROW_SALOME_CORBA_EXCEPTION( "invalid element id", SALOME::BAD_PARAM );
5055
5056   return ( SMESH::GeometryType ) e->GetGeomType();
5057 }
5058
5059 //=============================================================================
5060 /*!
5061  * Return ID of elements for given submesh
5062  */
5063 //=============================================================================
5064
5065 SMESH::smIdType_array* SMESH_Mesh_i::GetSubMeshElementsId(const CORBA::Long ShapeID)
5066 {
5067   SMESH::smIdType_array_var aResult = new SMESH::smIdType_array();
5068
5069   SMESH_TRY;
5070   if ( _preMeshInfo )
5071     _preMeshInfo->FullLoadFromFile();
5072
5073   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
5074   if(!SM) return aResult._retn();
5075
5076   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
5077   if(!SDSM) return aResult._retn();
5078
5079   aResult->length(SDSM->NbElements());
5080
5081   SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
5082   smIdType i = 0;
5083   while ( eIt->more() ) {
5084     aResult[i++] = eIt->next()->GetID();
5085   }
5086
5087   SMESH_CATCH( SMESH::throwCorbaException );
5088
5089   return aResult._retn();
5090 }
5091
5092 //=============================================================================
5093 /*!
5094  * Return ID of nodes for given sub-mesh
5095  * If param all==true - return all nodes, else -
5096  * Return only nodes on shapes.
5097  */
5098 //=============================================================================
5099
5100 SMESH::smIdType_array* SMESH_Mesh_i::GetSubMeshNodesId(const CORBA::Long ShapeID,
5101                                                    CORBA::Boolean    all)
5102 {
5103   SMESH::smIdType_array_var aResult = new SMESH::smIdType_array();
5104
5105   SMESH_TRY;
5106   if ( _preMeshInfo )
5107     _preMeshInfo->FullLoadFromFile();
5108
5109   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
5110   if(!SM) return aResult._retn();
5111
5112   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
5113   if(!SDSM) return aResult._retn();
5114
5115   set<smIdType> theElems;
5116   if( !all || (SDSM->NbElements()==0) ) { // internal nodes or vertex submesh
5117     SMDS_NodeIteratorPtr nIt = SDSM->GetNodes();
5118     while ( nIt->more() ) {
5119       const SMDS_MeshNode* elem = nIt->next();
5120       theElems.insert( elem->GetID() );
5121     }
5122   }
5123   else { // all nodes of submesh elements
5124     SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
5125     while ( eIt->more() ) {
5126       const SMDS_MeshElement* anElem = eIt->next();
5127       SMDS_ElemIteratorPtr nIt = anElem->nodesIterator();
5128       while ( nIt->more() ) {
5129         const SMDS_MeshElement* elem = nIt->next();
5130         theElems.insert( elem->GetID() );
5131       }
5132     }
5133   }
5134
5135   aResult->length(theElems.size());
5136   set<smIdType>::iterator itElem;
5137   smIdType i = 0;
5138   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5139     aResult[i++] = *itElem;
5140
5141   SMESH_CATCH( SMESH::throwCorbaException );
5142
5143   return aResult._retn();
5144 }
5145
5146 //=============================================================================
5147 /*!
5148  * Return type of elements for given sub-mesh
5149  */
5150 //=============================================================================
5151
5152 SMESH::ElementType SMESH_Mesh_i::GetSubMeshElementType(const CORBA::Long ShapeID)
5153 {
5154   SMESH::ElementType type = SMESH::ALL;
5155
5156   SMESH_TRY;
5157   if ( _preMeshInfo )
5158     _preMeshInfo->FullLoadFromFile();
5159
5160   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
5161   if(!SM) return SMESH::ALL;
5162
5163   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
5164   if(!SDSM) return SMESH::ALL;
5165
5166   if(SDSM->NbElements()==0)
5167     return (SM->GetSubShape().ShapeType() == TopAbs_VERTEX) ? SMESH::NODE : SMESH::ALL;
5168
5169   SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
5170   const SMDS_MeshElement* anElem = eIt->next();
5171
5172   type = ( SMESH::ElementType ) anElem->GetType();
5173
5174   SMESH_CATCH( SMESH::throwCorbaException );
5175
5176   return type;
5177 }
5178
5179
5180 //=============================================================================
5181 /*!
5182  * Return pointer to _impl as an integer value. Is called from constructor of SMESH_Client
5183  */
5184 //=============================================================================
5185
5186 CORBA::LongLong SMESH_Mesh_i::GetMeshPtr()
5187 {
5188   if ( _preMeshInfo )
5189     _preMeshInfo->FullLoadFromFile();
5190
5191   CORBA::LongLong pointeur = CORBA::LongLong(_impl);
5192   if ( MYDEBUG ) MESSAGE("CORBA::LongLong SMESH_Mesh_i::GetMeshPtr() "<<pointeur);
5193   return pointeur;
5194 }
5195
5196
5197 //=============================================================================
5198 /*!
5199  * Get XYZ coordinates of node as list of double
5200  * If there is not node for given ID - return empty list
5201  */
5202 //=============================================================================
5203
5204 SMESH::double_array* SMESH_Mesh_i::GetNodeXYZ(const SMESH::smIdType id)
5205 {
5206   if ( _preMeshInfo )
5207     _preMeshInfo->FullLoadFromFile();
5208
5209   SMESH::double_array_var aResult = new SMESH::double_array();
5210   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5211   if ( aMeshDS == NULL )
5212     return aResult._retn();
5213
5214   // find node
5215   const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
5216   if(!aNode)
5217     return aResult._retn();
5218
5219   // add coordinates
5220   aResult->length(3);
5221   aResult[0] = aNode->X();
5222   aResult[1] = aNode->Y();
5223   aResult[2] = aNode->Z();
5224   return aResult._retn();
5225 }
5226
5227
5228 //=============================================================================
5229 /*!
5230  * For given node return list of IDs of inverse elements
5231  * If there is not node for given ID - return empty list
5232  */
5233 //=============================================================================
5234
5235 SMESH::smIdType_array* SMESH_Mesh_i::GetNodeInverseElements(const SMESH::smIdType  id,
5236                                                             SMESH::ElementType elemType)
5237 {
5238   if ( _preMeshInfo )
5239     _preMeshInfo->FullLoadFromFile();
5240
5241   SMESH::smIdType_array_var aResult = new SMESH::smIdType_array();
5242   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5243   if ( aMeshDS == NULL )
5244     return aResult._retn();
5245
5246   // find node
5247   const SMDS_MeshNode* aNode = aMeshDS->FindNode( id );
5248   if ( !aNode )
5249     return aResult._retn();
5250
5251   // find inverse elements
5252   SMDSAbs_ElementType type = SMDSAbs_ElementType( elemType );
5253   SMDS_ElemIteratorPtr eIt = aNode->GetInverseElementIterator( type );
5254   aResult->length( aNode->NbInverseElements( type ));
5255   for( smIdType i = 0; eIt->more(); ++i )
5256   {
5257     const SMDS_MeshElement* elem = eIt->next();
5258     aResult[ i ] = elem->GetID();
5259   }
5260   return aResult._retn();
5261 }
5262
5263 //=============================================================================
5264 /*!
5265  * \brief Return position of a node on shape
5266  */
5267 //=============================================================================
5268
5269 SMESH::NodePosition* SMESH_Mesh_i::GetNodePosition(SMESH::smIdType NodeID)
5270 {
5271   if ( _preMeshInfo )
5272     _preMeshInfo->FullLoadFromFile();
5273
5274   SMESH::NodePosition* aNodePosition = new SMESH::NodePosition();
5275   aNodePosition->shapeID = 0;
5276   aNodePosition->shapeType = GEOM::SHAPE;
5277
5278   SMESHDS_Mesh* mesh = _impl->GetMeshDS();
5279   if ( !mesh ) return aNodePosition;
5280
5281   if ( const SMDS_MeshNode* aNode = mesh->FindNode(NodeID) )
5282   {
5283     if ( SMDS_PositionPtr pos = aNode->GetPosition() )
5284     {
5285       aNodePosition->shapeID = aNode->getshapeId();
5286       switch ( pos->GetTypeOfPosition() ) {
5287       case SMDS_TOP_EDGE:
5288         aNodePosition->shapeType = GEOM::EDGE;
5289         aNodePosition->params.length(1);
5290         aNodePosition->params[0] = SMDS_EdgePositionPtr( pos )->GetUParameter();
5291         break;
5292       case SMDS_TOP_FACE: {
5293         SMDS_FacePositionPtr fPos = pos;
5294         aNodePosition->shapeType = GEOM::FACE;
5295         aNodePosition->params.length(2);
5296         aNodePosition->params[0] = fPos->GetUParameter();
5297         aNodePosition->params[1] = fPos->GetVParameter();
5298         break;
5299       }
5300       case SMDS_TOP_VERTEX:
5301         aNodePosition->shapeType = GEOM::VERTEX;
5302         break;
5303       case SMDS_TOP_3DSPACE:
5304         if ( TopExp_Explorer(_impl->GetShapeToMesh(), TopAbs_SOLID).More() )
5305           aNodePosition->shapeType = GEOM::SOLID;
5306         else if ( TopExp_Explorer(_impl->GetShapeToMesh(), TopAbs_SHELL).More() )
5307           aNodePosition->shapeType = GEOM::SHELL;
5308         break;
5309       default:;
5310       }
5311     }
5312   }
5313   return aNodePosition;
5314 }
5315
5316 //=============================================================================
5317 /*!
5318  * \brief Return position of an element on shape
5319  */
5320 //=============================================================================
5321
5322 SMESH::ElementPosition SMESH_Mesh_i::GetElementPosition(SMESH::smIdType ElemID)
5323 {
5324   if ( _preMeshInfo )
5325     _preMeshInfo->FullLoadFromFile();
5326
5327   SMESH::ElementPosition anElementPosition;
5328   anElementPosition.shapeID = 0;
5329   anElementPosition.shapeType = GEOM::SHAPE;
5330
5331   SMESHDS_Mesh* mesh = _impl->GetMeshDS();
5332   if ( !mesh ) return anElementPosition;
5333
5334   if ( const SMDS_MeshElement* anElem = mesh->FindElement( ElemID ) )
5335   {
5336     anElementPosition.shapeID = anElem->getshapeId();
5337     const TopoDS_Shape& aSp = mesh->IndexToShape( anElem->getshapeId() );
5338     if ( !aSp.IsNull() ) {
5339       switch ( aSp.ShapeType() ) {
5340       case TopAbs_EDGE:
5341         anElementPosition.shapeType = GEOM::EDGE;
5342         break;
5343       case TopAbs_FACE:
5344         anElementPosition.shapeType = GEOM::FACE;
5345         break;
5346       case TopAbs_VERTEX:
5347         anElementPosition.shapeType = GEOM::VERTEX;
5348         break;
5349       case TopAbs_SOLID:
5350         anElementPosition.shapeType = GEOM::SOLID;
5351         break;
5352       case TopAbs_SHELL:
5353         anElementPosition.shapeType = GEOM::SHELL;
5354         break;
5355       default:;
5356       }
5357     }
5358   }
5359   return anElementPosition;
5360 }
5361
5362 //=============================================================================
5363 /*!
5364  * If given element is node return IDs of shape from position
5365  * If there is not node for given ID - return -1
5366  */
5367 //=============================================================================
5368
5369 CORBA::Long SMESH_Mesh_i::GetShapeID(const SMESH::smIdType id)
5370 {
5371   if ( _preMeshInfo )
5372     _preMeshInfo->FullLoadFromFile();
5373
5374   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5375   if ( aMeshDS == NULL )
5376     return -1;
5377
5378   // try to find node
5379   const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
5380   if(aNode) {
5381     return aNode->getshapeId();
5382   }
5383
5384   return -1;
5385 }
5386
5387
5388 //=============================================================================
5389 /*!
5390  * For given element return ID of result shape after
5391  * ::FindShape() from SMESH_MeshEditor
5392  * If there is not element for given ID - return -1
5393  */
5394 //=============================================================================
5395
5396 CORBA::Long SMESH_Mesh_i::GetShapeIDForElem(const SMESH::smIdType id)
5397 {
5398   if ( _preMeshInfo )
5399     _preMeshInfo->FullLoadFromFile();
5400
5401   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5402   if ( aMeshDS == NULL )
5403     return -1;
5404
5405   // try to find element
5406   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5407   if(!elem)
5408     return -1;
5409
5410   ::SMESH_MeshEditor aMeshEditor(_impl);
5411   int index = aMeshEditor.FindShape( elem );
5412   if(index>0)
5413     return index;
5414
5415   return -1;
5416 }
5417
5418
5419 //=============================================================================
5420 /*!
5421  * Return number of nodes for given element
5422  * If there is not element for given ID - return -1
5423  */
5424 //=============================================================================
5425
5426 CORBA::Short SMESH_Mesh_i::GetElemNbNodes(const SMESH::smIdType id)
5427 {
5428   if ( _preMeshInfo )
5429     _preMeshInfo->FullLoadFromFile();
5430
5431   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5432   if ( aMeshDS == NULL ) return -1;
5433   // try to find element
5434   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5435   if(!elem) return -1;
5436   return elem->NbNodes();
5437 }
5438
5439
5440 //=============================================================================
5441 /*!
5442  * Return ID of node by given index for given element
5443  * If there is not element for given ID - return -1
5444  * If there is not node for given index - return -2
5445  */
5446 //=============================================================================
5447
5448 SMESH::smIdType SMESH_Mesh_i::GetElemNode(const SMESH::smIdType id, const CORBA::Short index)
5449 {
5450   if ( _preMeshInfo )
5451     _preMeshInfo->FullLoadFromFile();
5452
5453   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5454   if ( aMeshDS == NULL ) return -1;
5455   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5456   if(!elem) return -1;
5457   if( index>=elem->NbNodes() || index<0 ) return -1;
5458   return elem->GetNode(index)->GetID();
5459 }
5460
5461 //=============================================================================
5462 /*!
5463  * Return IDs of nodes of given element
5464  */
5465 //=============================================================================
5466
5467 SMESH::smIdType_array* SMESH_Mesh_i::GetElemNodes(const SMESH::smIdType id)
5468 {
5469   if ( _preMeshInfo )
5470     _preMeshInfo->FullLoadFromFile();
5471
5472   SMESH::smIdType_array_var aResult = new SMESH::smIdType_array();
5473   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() )
5474   {
5475     if ( const SMDS_MeshElement* elem = aMeshDS->FindElement(id) )
5476     {
5477       aResult->length( elem->NbNodes() );
5478       for ( CORBA::ULong i = 0; i < aResult->length(); ++i )
5479         if ( const SMDS_MeshNode* n = elem->GetNode( i ))
5480           aResult[ i ] = n->GetID();
5481     }
5482   }
5483   return aResult._retn();
5484 }
5485
5486 //=============================================================================
5487 /*!
5488  * Return true if given node is medium node
5489  * in given quadratic element
5490  */
5491 //=============================================================================
5492
5493 CORBA::Boolean SMESH_Mesh_i::IsMediumNode(const SMESH::smIdType ide, const SMESH::smIdType idn)
5494 {
5495   if ( _preMeshInfo )
5496     _preMeshInfo->FullLoadFromFile();
5497
5498   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5499   if ( aMeshDS == NULL ) return false;
5500   // try to find node
5501   const SMDS_MeshNode* aNode = aMeshDS->FindNode(idn);
5502   if(!aNode) return false;
5503   // try to find element
5504   const SMDS_MeshElement* elem = aMeshDS->FindElement(ide);
5505   if(!elem) return false;
5506
5507   return elem->IsMediumNode(aNode);
5508 }
5509
5510
5511 //=============================================================================
5512 /*!
5513  * Return true if given node is medium node
5514  * in one of quadratic elements
5515  */
5516 //=============================================================================
5517
5518 CORBA::Boolean SMESH_Mesh_i::IsMediumNodeOfAnyElem(const SMESH::smIdType idn,
5519                                                    SMESH::ElementType theElemType)
5520 {
5521   if ( _preMeshInfo )
5522     _preMeshInfo->FullLoadFromFile();
5523
5524   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5525   if ( aMeshDS == NULL ) return false;
5526
5527   // try to find node
5528   const SMDS_MeshNode* aNode = aMeshDS->FindNode(idn);
5529   if(!aNode) return false;
5530
5531   SMESH_MesherHelper aHelper( *(_impl) );
5532
5533   SMDSAbs_ElementType aType;
5534   if(theElemType==SMESH::EDGE) aType = SMDSAbs_Edge;
5535   else if(theElemType==SMESH::FACE) aType = SMDSAbs_Face;
5536   else if(theElemType==SMESH::VOLUME) aType = SMDSAbs_Volume;
5537   else aType = SMDSAbs_All;
5538
5539   return aHelper.IsMedium(aNode,aType);
5540 }
5541
5542
5543 //=============================================================================
5544 /*!
5545  * Return number of edges for given element
5546  */
5547 //=============================================================================
5548
5549 CORBA::Long SMESH_Mesh_i::ElemNbEdges(const SMESH::smIdType id)
5550 {
5551   if ( _preMeshInfo )
5552     _preMeshInfo->FullLoadFromFile();
5553
5554   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5555   if ( aMeshDS == NULL ) return -1;
5556   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5557   if(!elem) return -1;
5558   return elem->NbEdges();
5559 }
5560
5561
5562 //=============================================================================
5563 /*!
5564  * Return number of faces for given element
5565  */
5566 //=============================================================================
5567
5568 CORBA::Long SMESH_Mesh_i::ElemNbFaces(const SMESH::smIdType id)
5569 {
5570   if ( _preMeshInfo )
5571     _preMeshInfo->FullLoadFromFile();
5572
5573   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5574   if ( aMeshDS == NULL ) return -1;
5575   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5576   if(!elem) return -1;
5577   return elem->NbFaces();
5578 }
5579
5580 //================================================================================
5581 /*!
5582  * \brief Return nodes of given face (counted from zero) for given element.
5583  */
5584 //================================================================================
5585
5586 SMESH::smIdType_array* SMESH_Mesh_i::GetElemFaceNodes(SMESH::smIdType  elemId,
5587                                                       CORBA::Short     faceIndex)
5588 {
5589   if ( _preMeshInfo )
5590     _preMeshInfo->FullLoadFromFile();
5591
5592   SMESH::smIdType_array_var aResult = new SMESH::smIdType_array();
5593   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() )
5594   {
5595     if ( const SMDS_MeshElement* elem = aMeshDS->FindElement(elemId) )
5596     {
5597       SMDS_VolumeTool vtool( elem, /*skipCentralNodes = */false );
5598       if ( faceIndex < vtool.NbFaces() )
5599       {
5600         aResult->length( vtool.NbFaceNodes( faceIndex ));
5601         const SMDS_MeshNode** nn = vtool.GetFaceNodes( faceIndex );
5602         for ( CORBA::ULong i = 0; i < aResult->length(); ++i )
5603           aResult[ i ] = nn[ i ]->GetID();
5604       }
5605     }
5606   }
5607   return aResult._retn();
5608 }
5609
5610 //================================================================================
5611 /*!
5612  * \brief Return three components of normal of given mesh face.
5613  */
5614 //================================================================================
5615
5616 SMESH::double_array* SMESH_Mesh_i::GetFaceNormal(CORBA::Long    elemId,
5617                                                  CORBA::Boolean normalized)
5618 {
5619   if ( _preMeshInfo )
5620     _preMeshInfo->FullLoadFromFile();
5621
5622   SMESH::double_array_var aResult = new SMESH::double_array();
5623
5624   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5625   {
5626     gp_XYZ normal;
5627     if ( SMESH_MeshAlgos::FaceNormal( mesh->FindElement(elemId), normal, normalized ))
5628     {
5629       aResult->length( 3 );
5630       aResult[ 0 ] = normal.X();
5631       aResult[ 1 ] = normal.Y();
5632       aResult[ 2 ] = normal.Z();
5633     }
5634   }
5635   return aResult._retn();
5636 }
5637
5638 //================================================================================
5639 /*!
5640  * \brief Return an element based on all given nodes.
5641  */
5642 //================================================================================
5643
5644 SMESH::smIdType SMESH_Mesh_i::FindElementByNodes(const SMESH::smIdType_array& nodes)
5645 {
5646   if ( _preMeshInfo )
5647     _preMeshInfo->FullLoadFromFile();
5648
5649   CORBA::Long elemID(0);
5650   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5651   {
5652     vector< const SMDS_MeshNode * > nn( nodes.length() );
5653     for ( CORBA::ULong i = 0; i < nodes.length(); ++i )
5654       if ( !( nn[i] = mesh->FindNode( nodes[i] )))
5655         return elemID;
5656
5657     const SMDS_MeshElement* elem = mesh->FindElement( nn, SMDSAbs_All, /*noMedium=*/false );
5658     if ( !elem && ( _impl->NbEdges  ( ORDER_QUADRATIC ) ||
5659                     _impl->NbFaces  ( ORDER_QUADRATIC ) ||
5660                     _impl->NbVolumes( ORDER_QUADRATIC )))
5661       elem = mesh->FindElement( nn, SMDSAbs_All, /*noMedium=*/true );
5662
5663     if ( elem ) elemID = CORBA::Long( elem->GetID() );
5664   }
5665   return elemID;
5666 }
5667
5668 //================================================================================
5669 /*!
5670  * \brief Return elements including all given nodes.
5671  */
5672 //================================================================================
5673
5674 SMESH::smIdType_array* SMESH_Mesh_i::GetElementsByNodes(const SMESH::smIdType_array& nodes,
5675                                                         SMESH::ElementType       elemType)
5676 {
5677   if ( _preMeshInfo )
5678     _preMeshInfo->FullLoadFromFile();
5679
5680   SMESH::smIdType_array_var result = new SMESH::smIdType_array();
5681
5682   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5683   {
5684     vector< const SMDS_MeshNode * > nn( nodes.length() );
5685     for ( CORBA::ULong i = 0; i < nodes.length(); ++i )
5686       nn[i] = mesh->FindNode( nodes[i] );
5687
5688     std::vector<const SMDS_MeshElement *> elems;
5689     mesh->GetElementsByNodes( nn, elems, (SMDSAbs_ElementType) elemType );
5690     result->length( elems.size() );
5691     for ( size_t i = 0; i < elems.size(); ++i )
5692       result[i] = elems[i]->GetID();
5693   }
5694   return result._retn();
5695 }
5696
5697 //=============================================================================
5698 /*!
5699  * Return true if given element is polygon
5700  */
5701 //=============================================================================
5702
5703 CORBA::Boolean SMESH_Mesh_i::IsPoly(const SMESH::smIdType id)
5704 {
5705   if ( _preMeshInfo )
5706     _preMeshInfo->FullLoadFromFile();
5707
5708   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5709   if ( aMeshDS == NULL ) return false;
5710   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5711   if(!elem) return false;
5712   return elem->IsPoly();
5713 }
5714
5715
5716 //=============================================================================
5717 /*!
5718  * Return true if given element is quadratic
5719  */
5720 //=============================================================================
5721
5722 CORBA::Boolean SMESH_Mesh_i::IsQuadratic(const SMESH::smIdType id)
5723 {
5724   if ( _preMeshInfo )
5725     _preMeshInfo->FullLoadFromFile();
5726
5727   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5728   if ( aMeshDS == NULL ) return false;
5729   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5730   if(!elem) return false;
5731   return elem->IsQuadratic();
5732 }
5733
5734 //=============================================================================
5735 /*!
5736  * Return diameter of ball discrete element or zero in case of an invalid \a id
5737  */
5738 //=============================================================================
5739
5740 CORBA::Double SMESH_Mesh_i::GetBallDiameter(SMESH::smIdType id)
5741 {
5742   if ( _preMeshInfo )
5743     _preMeshInfo->FullLoadFromFile();
5744
5745   if ( const SMDS_BallElement* ball =
5746        SMDS_Mesh::DownCast<SMDS_BallElement>( _impl->GetMeshDS()->FindElement( id )))
5747     return ball->GetDiameter();
5748
5749   return 0;
5750 }
5751
5752 //=============================================================================
5753 /*!
5754  * Return bary center for given element
5755  */
5756 //=============================================================================
5757
5758 SMESH::double_array* SMESH_Mesh_i::BaryCenter(const SMESH::smIdType id)
5759 {
5760   if ( _preMeshInfo )
5761     _preMeshInfo->FullLoadFromFile();
5762
5763   SMESH::double_array_var aResult = new SMESH::double_array();
5764   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5765   if ( aMeshDS == NULL )
5766     return aResult._retn();
5767
5768   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5769   if(!elem)
5770     return aResult._retn();
5771
5772   if(elem->GetType()==SMDSAbs_Volume) {
5773     SMDS_VolumeTool aTool;
5774     if(aTool.Set(elem)) {
5775       aResult->length(3);
5776       if (!aTool.GetBaryCenter( aResult[0], aResult[1], aResult[2]) )
5777         aResult->length(0);
5778     }
5779   }
5780   else {
5781     SMDS_ElemIteratorPtr anIt = elem->nodesIterator();
5782     int nbn = 0;
5783     double x=0., y=0., z=0.;
5784     for(; anIt->more(); ) {
5785       nbn++;
5786       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(anIt->next());
5787       x += aNode->X();
5788       y += aNode->Y();
5789       z += aNode->Z();
5790     }
5791     if(nbn>0) {
5792       // add coordinates
5793       aResult->length(3);
5794       aResult[0] = x/nbn;
5795       aResult[1] = y/nbn;
5796       aResult[2] = z/nbn;
5797     }
5798   }
5799
5800   return aResult._retn();
5801 }
5802
5803 //================================================================================
5804 /*!
5805  * \brief Create a group of elements preventing computation of a sub-shape
5806  */
5807 //================================================================================
5808
5809 SMESH::ListOfGroups*
5810 SMESH_Mesh_i::MakeGroupsOfBadInputElements( int         theSubShapeID,
5811                                             const char* theGroupName )
5812 {
5813   Unexpect aCatch(SALOME_SalomeException);
5814
5815   if ( !theGroupName || strlen( theGroupName) == 0 )
5816     THROW_SALOME_CORBA_EXCEPTION( "empty group name",SALOME::BAD_PARAM );
5817
5818   SMESH::ListOfGroups_var groups = new SMESH::ListOfGroups;
5819   ::SMESH_MeshEditor::ElemFeatures elemType;
5820
5821   // submesh by subshape id
5822   if ( !_impl->HasShapeToMesh() ) theSubShapeID = 1;
5823   if ( SMESH_subMesh * sm = _impl->GetSubMeshContaining( theSubShapeID ))
5824   {
5825     // compute error
5826     SMESH_ComputeErrorPtr error = sm->GetComputeError();
5827     if ( error && error->HasBadElems() )
5828     {
5829       // sort bad elements by type
5830       vector< const SMDS_MeshElement* > elemsByType[ SMDSAbs_NbElementTypes ];
5831       const list<const SMDS_MeshElement*>& badElems =
5832         static_cast<SMESH_BadInputElements*>( error.get() )->myBadElements;
5833       list<const SMDS_MeshElement*>::const_iterator elemIt  = badElems.begin();
5834       list<const SMDS_MeshElement*>::const_iterator elemEnd = badElems.end();
5835       for ( ; elemIt != elemEnd; ++elemIt )
5836       {
5837         const SMDS_MeshElement* elem = *elemIt;
5838         if ( !elem ) continue;
5839
5840         if ( elem->GetID() < 1 )
5841         {
5842           // elem is a temporary element, make a real element
5843           vector< const SMDS_MeshNode* > nodes;
5844           SMDS_NodeIteratorPtr nIt = elem->nodeIterator();
5845           while ( nIt->more() && elem )
5846           {
5847             nodes.push_back( nIt->next() );
5848             if ( nodes.back()->GetID() < 1 )
5849               elem = 0;  // a temporary element on temporary nodes
5850           }
5851           if ( elem )
5852           {
5853             ::SMESH_MeshEditor editor( _impl );
5854             elem = editor.AddElement( nodes, elemType.Init( elem ));
5855           }
5856         }
5857         if ( elem )
5858           elemsByType[ elem->GetType() ].push_back( elem );
5859       }
5860
5861       // how many groups to create?
5862       int nbTypes = 0;
5863       for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
5864         nbTypes += int( !elemsByType[ i ].empty() );
5865       groups->length( nbTypes );
5866
5867       // create groups
5868       for ( int i = 0, iG = -1; i < SMDSAbs_NbElementTypes; ++i )
5869       {
5870         vector< const SMDS_MeshElement* >& elems = elemsByType[ i ];
5871         if ( elems.empty() ) continue;
5872
5873         groups[ ++iG ] = createGroup( SMESH::ElementType(i), theGroupName );
5874         if ( _gen_i->CanPublishInStudy( groups[ iG ] ))
5875         {
5876           SMESH::SMESH_Mesh_var mesh = _this();
5877           SALOMEDS::SObject_wrap aSO =
5878             _gen_i->PublishGroup( mesh, groups[ iG ],
5879                                  GEOM::GEOM_Object::_nil(), theGroupName);
5880         }
5881         SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( groups[ iG ]);
5882         if ( !grp_i ) continue;
5883
5884         if ( SMESHDS_Group*  grpDS = dynamic_cast< SMESHDS_Group* >( grp_i->GetGroupDS() ))
5885           for ( size_t iE = 0; iE < elems.size(); ++iE )
5886             grpDS->SMDSGroup().Add( elems[ iE ]);
5887       }
5888     }
5889   }
5890
5891   return groups._retn();
5892 }
5893
5894 //=============================================================================
5895 /*!
5896  * Create and publish group servants if any groups were imported or created anyhow
5897  */
5898 //=============================================================================
5899
5900 void SMESH_Mesh_i::CreateGroupServants()
5901 {
5902   SMESH::SMESH_Mesh_var aMesh = _this();
5903
5904   set<int> addedIDs;
5905   ::SMESH_Mesh::GroupIteratorPtr groupIt = _impl->GetGroups();
5906   while ( groupIt->more() )
5907   {
5908     ::SMESH_Group* group = groupIt->next();
5909     int             anId = group->GetID();
5910
5911     map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.find(anId);
5912     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
5913       continue;
5914     addedIDs.insert( anId );
5915
5916     SMESH_GroupBase_i* aGroupImpl;
5917     TopoDS_Shape       shape;
5918     if ( SMESHDS_GroupOnGeom* groupOnGeom =
5919          dynamic_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() ))
5920     {
5921       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
5922       shape      = groupOnGeom->GetShape();
5923     }
5924     else {
5925       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
5926     }
5927
5928     SMESH::SMESH_GroupBase_var groupVar = aGroupImpl->_this();
5929     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( groupVar );
5930     aGroupImpl->Register();
5931
5932     // register CORBA object for persistence
5933     int nextId = _gen_i->RegisterObject( groupVar );
5934     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
5935     else        { (void)nextId; } // avoid "unused variable" warning in release mode
5936
5937     // publishing the groups in the study
5938     GEOM::GEOM_Object_var shapeVar = _gen_i->ShapeToGeomObject( shape );
5939     _gen_i->PublishGroup( aMesh, groupVar, shapeVar, group->GetName());
5940   }
5941
5942   if ( !addedIDs.empty() )
5943   {
5944     // python dump
5945     map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.begin();
5946     for ( int index = 0; i_grp != _mapGroups.end(); ++index, ++i_grp )
5947     {
5948       set<int>::iterator it = addedIDs.find( i_grp->first );
5949       if ( it != addedIDs.end() )
5950       {
5951         TPythonDump() << i_grp->second << " = " << aMesh << ".GetGroups()[ "<< index << " ]";
5952         addedIDs.erase( it );
5953         if ( addedIDs.empty() )
5954           break;
5955       }
5956     }
5957   }
5958 }
5959
5960 //=============================================================================
5961 /*!
5962  * \brief Return true if all sub-meshes are computed OK - to update an icon
5963  */
5964 //=============================================================================
5965
5966 bool SMESH_Mesh_i::IsComputedOK()
5967 {
5968   return _impl->IsComputedOK();
5969 }
5970
5971 //=============================================================================
5972 /*!
5973  * \brief Return groups cantained in _mapGroups by their IDs
5974  */
5975 //=============================================================================
5976
5977 SMESH::ListOfGroups* SMESH_Mesh_i::GetGroups(const list<int>& groupIDs) const
5978 {
5979   int nbGroups = groupIDs.size();
5980   SMESH::ListOfGroups_var aList = new SMESH::ListOfGroups();
5981   aList->length( nbGroups );
5982
5983   list<int>::const_iterator ids = groupIDs.begin();
5984   for ( nbGroups = 0; ids != groupIDs.end(); ++ids )
5985   {
5986     map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator it = _mapGroups.find( *ids );
5987     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
5988       aList[nbGroups++] = SMESH::SMESH_GroupBase::_duplicate( it->second );
5989   }
5990   aList->length( nbGroups );
5991   return aList._retn();
5992 }
5993
5994 //=============================================================================
5995 /*!
5996  * \brief Return information about imported file
5997  */
5998 //=============================================================================
5999
6000 SMESH::MedFileInfo* SMESH_Mesh_i::GetMEDFileInfo()
6001 {
6002   SMESH::MedFileInfo_var res( _medFileInfo );
6003   if ( !res.operator->() ) {
6004     res = new SMESH::MedFileInfo;
6005     res->fileName = "";
6006     res->fileSize = res->major = res->minor = res->release = -1;
6007   }
6008   return res._retn();
6009 }
6010
6011 //=======================================================================
6012 //function : FileInfoToString
6013 //purpose  : Persistence of file info
6014 //=======================================================================
6015
6016 std::string SMESH_Mesh_i::FileInfoToString()
6017 {
6018   std::string s;
6019   if ( &_medFileInfo.in() && _medFileInfo->fileName[0] )
6020   {
6021     s = SMESH_Comment( _medFileInfo->fileSize )
6022       << " " << _medFileInfo->major
6023       << " " << _medFileInfo->minor
6024       << " " << _medFileInfo->release
6025       << " " << _medFileInfo->fileName;
6026   }
6027   return s;
6028 }
6029
6030 //=======================================================================
6031 //function : FileInfoFromString
6032 //purpose  : Persistence of file info
6033 //=======================================================================
6034
6035 void SMESH_Mesh_i::FileInfoFromString(const std::string& info)
6036 {
6037   std::string size, major, minor, release, fileName;
6038   std::istringstream is(info);
6039   is >> size >> major >> minor >> release;
6040   fileName = info.data() + ( size.size()   + 1 +
6041                              major.size()  + 1 +
6042                              minor.size()  + 1 +
6043                              release.size()+ 1 );
6044
6045   _medFileInfo           = new SMESH::MedFileInfo();
6046   _medFileInfo->fileName = fileName.c_str();
6047   _medFileInfo->fileSize = atoi( size.c_str() );
6048   _medFileInfo->major    = atoi( major.c_str() );
6049   _medFileInfo->minor    = atoi( minor.c_str() );
6050   _medFileInfo->release  = atoi( release.c_str() );
6051 }
6052
6053 //=============================================================================
6054 /*!
6055  * \brief Pass names of mesh groups from study to mesh DS
6056  */
6057 //=============================================================================
6058
6059 void SMESH_Mesh_i::checkGroupNames()
6060 {
6061   int nbGrp = NbGroups();
6062   if ( !nbGrp )
6063     return;
6064
6065   SMESH::ListOfGroups* grpList = 0;
6066   // avoid dump of "GetGroups"
6067   {
6068     // store python dump into a local variable inside local scope
6069     SMESH::TPythonDump pDump; // do not delete this line of code
6070     grpList = GetGroups();
6071   }
6072
6073   for ( int gIndx = 0; gIndx < nbGrp; gIndx++ ) {
6074     SMESH::SMESH_GroupBase_ptr aGrp = (*grpList)[ gIndx ];
6075     if ( !aGrp )
6076       continue;
6077     SALOMEDS::SObject_wrap aGrpSO = _gen_i->ObjectToSObject( aGrp );
6078     if ( aGrpSO->_is_nil() )
6079       continue;
6080     // correct name of the mesh group if necessary
6081     const char* guiName = aGrpSO->GetName();
6082     if ( strcmp(guiName, aGrp->GetName()) )
6083       aGrp->SetName( guiName );
6084   }
6085 }
6086
6087 //=============================================================================
6088 /*!
6089  * \brief Set list of notebook variables used for Mesh operations separated by ":" symbol
6090  */
6091 //=============================================================================
6092 void SMESH_Mesh_i::SetParameters(const char* theParameters)
6093 {
6094   SMESH_Gen_i::GetSMESHGen()->UpdateParameters( CORBA::Object_var( _this() ).in(),
6095                                                 theParameters );
6096 }
6097
6098 //=============================================================================
6099 /*!
6100  * \brief Return list of notebook variables used for Mesh operations separated by ":" symbol
6101  */
6102 //=============================================================================
6103
6104 char* SMESH_Mesh_i::GetParameters()
6105 {
6106   return SMESH_Gen_i::GetSMESHGen()->GetParameters( SMESH::SMESH_Mesh_var( _this()) );
6107 }
6108
6109 //=============================================================================
6110 /*!
6111  * \brief Return list of notebook variables used for last Mesh operation
6112  */
6113 //=============================================================================
6114 SMESH::string_array* SMESH_Mesh_i::GetLastParameters()
6115 {
6116   SMESH::string_array_var aResult = new SMESH::string_array();
6117   SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen();
6118   if(gen) {
6119     CORBA::String_var aParameters = GetParameters();
6120     SALOMEDS::ListOfListOfStrings_var aSections = SMESH_Gen_i::GetSMESHGen()->getStudyServant()->ParseVariables(aParameters);
6121     if ( aSections->length() > 0 ) {
6122       SALOMEDS::ListOfStrings aVars = aSections[ aSections->length() - 1 ];
6123       aResult->length( aVars.length() );
6124       for ( CORBA::ULong i = 0;i < aVars.length(); i++ )
6125         aResult[i] = CORBA::string_dup( aVars[i] );
6126     }
6127   }
6128   return aResult._retn();
6129 }
6130
6131 //================================================================================
6132 /*!
6133  * \brief Return types of elements it contains
6134  */
6135 //================================================================================
6136
6137 SMESH::array_of_ElementType* SMESH_Mesh_i::GetTypes()
6138 {
6139   if ( _preMeshInfo )
6140     return _preMeshInfo->GetTypes();
6141
6142   SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType;
6143
6144   types->length( 5 );
6145   int nbTypes = 0;
6146   if (_impl->NbEdges())      types[nbTypes++] = SMESH::EDGE;
6147   if (_impl->NbFaces())      types[nbTypes++] = SMESH::FACE;
6148   if (_impl->NbVolumes())    types[nbTypes++] = SMESH::VOLUME;
6149   if (_impl->Nb0DElements()) types[nbTypes++] = SMESH::ELEM0D;
6150   if (_impl->NbBalls())      types[nbTypes++] = SMESH::BALL;
6151   if (_impl->NbNodes() &&
6152       nbTypes == 0 )         types[nbTypes++] = SMESH::NODE;
6153   types->length( nbTypes );
6154
6155   return types._retn();
6156 }
6157
6158 //================================================================================
6159 /*!
6160  * \brief Return self
6161  */
6162 //================================================================================
6163
6164 SMESH::SMESH_Mesh_ptr SMESH_Mesh_i::GetMesh()
6165 {
6166   return SMESH::SMESH_Mesh::_duplicate( _this() );
6167 }
6168
6169 //================================================================================
6170 /*!
6171  * \brief Return false if GetMeshInfo() return incorrect information that may
6172  *        happen if mesh data is not yet fully loaded from the file of study.
6173  * 
6174  * 
6175  */
6176 //================================================================================
6177
6178 bool SMESH_Mesh_i::IsMeshInfoCorrect()
6179 {
6180   return _preMeshInfo ? _preMeshInfo->IsMeshInfoCorrect() : true;
6181 }
6182
6183 //=============================================================================
6184 /*!
6185  * \brief Return number of mesh elements per each \a EntityType
6186  */
6187 //=============================================================================
6188
6189 SMESH::smIdType_array* SMESH_Mesh_i::GetMeshInfo()
6190 {
6191   if ( _preMeshInfo )
6192     return _preMeshInfo->GetMeshInfo();
6193
6194   SMESH::smIdType_array_var aRes = new SMESH::smIdType_array();
6195   aRes->length(SMESH::Entity_Last);
6196   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
6197     aRes[i] = 0;
6198   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
6199   if (!aMeshDS)
6200     return aRes._retn();
6201   const SMDS_MeshInfo& aMeshInfo = aMeshDS->GetMeshInfo();
6202   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
6203     aRes[i] = aMeshInfo.NbEntities((SMDSAbs_EntityType)i);
6204   return aRes._retn();
6205 }
6206
6207 //=============================================================================
6208 /*!
6209  * \brief Return number of mesh elements per each \a ElementType
6210  */
6211 //=============================================================================
6212
6213 SMESH::smIdType_array* SMESH_Mesh_i::GetNbElementsByType()
6214 {
6215   SMESH::smIdType_array_var aRes = new SMESH::smIdType_array();
6216   aRes->length(SMESH::NB_ELEMENT_TYPES);
6217   for (smIdType i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
6218     aRes[ i ] = 0;
6219
6220   const SMDS_MeshInfo* meshInfo = 0;
6221   if ( _preMeshInfo )
6222     meshInfo = _preMeshInfo;
6223   else if ( SMESHDS_Mesh* meshDS = _impl->GetMeshDS() )
6224     meshInfo = & meshDS->GetMeshInfo();
6225
6226   if (meshInfo)
6227     for (smIdType i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
6228       aRes[i] = meshInfo->NbElements((SMDSAbs_ElementType)i);
6229
6230   return aRes._retn();
6231 }
6232
6233 //=============================================================================
6234 /*
6235  * Collect statistic of mesh elements given by iterator
6236  */
6237 //=============================================================================
6238
6239 void SMESH_Mesh_i::CollectMeshInfo(const SMDS_ElemIteratorPtr theItr,
6240                                    SMESH::smIdType_array&     theInfo)
6241 {
6242   if (!theItr) return;
6243   while (theItr->more())
6244     theInfo[ theItr->next()->GetEntityType() ]++;
6245 }
6246 //=============================================================================
6247 /*
6248  * Return mesh unstructed grid information.
6249  */
6250 //=============================================================================
6251
6252 SALOMEDS::TMPFile* SMESH_Mesh_i::GetVtkUgStream()
6253 {
6254   SALOMEDS::TMPFile_var SeqFile;
6255   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() ) {
6256     SMDS_UnstructuredGrid* aGrid = aMeshDS->GetGrid();
6257     if(aGrid) {
6258       vtkUnstructuredGridWriter* aWriter = vtkUnstructuredGridWriter::New();
6259       aWriter->WriteToOutputStringOn();
6260       aWriter->SetInputData(aGrid);
6261       aWriter->SetFileTypeToBinary();
6262       aWriter->Write();
6263       char* str = aWriter->GetOutputString();
6264       int size = aWriter->GetOutputStringLength();
6265
6266       //Allocate octet buffer of required size
6267       CORBA::Octet* OctetBuf = SALOMEDS::TMPFile::allocbuf(size);
6268       //Copy ostrstream content to the octet buffer
6269       memcpy(OctetBuf, str, size);
6270       //Create and return TMPFile
6271       SeqFile = new SALOMEDS::TMPFile(size, size, OctetBuf, 1);
6272       aWriter->Delete();
6273     }
6274   }
6275   return SeqFile._retn();
6276 }
6277
6278 //=============================================================================
6279 namespace /* Iterators used in SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_var obj,
6280            *                                             SMESH::ElementType        type) */
6281 {
6282   using namespace SMESH::Controls;
6283   //-----------------------------------------------------------------------------
6284   struct PredicateIterator : public SMDS_ElemIterator
6285   {
6286     SMDS_ElemIteratorPtr    _elemIter;
6287     PredicatePtr            _predicate;
6288     const SMDS_MeshElement* _elem;
6289     SMDSAbs_ElementType     _type;
6290
6291     PredicateIterator( SMDS_ElemIteratorPtr iterator,
6292                        PredicatePtr         predicate,
6293                        SMDSAbs_ElementType  type):
6294       _elemIter(iterator), _predicate(predicate), _type(type)
6295     {
6296       next();
6297     }
6298     virtual bool more()
6299     {
6300       return _elem;
6301     }
6302     virtual const SMDS_MeshElement* next()
6303     {
6304       const SMDS_MeshElement* res = _elem;
6305       _elem = 0;
6306       while ( _elemIter->more() && !_elem )
6307       {
6308         if ((_elem = _elemIter->next()) &&
6309             (( _type != SMDSAbs_All && _type != _elem->GetType() ) ||
6310              ( !_predicate->IsSatisfy( _elem->GetID() ))))
6311           _elem = 0;
6312       }
6313       return res;
6314     }
6315   };
6316
6317   //-----------------------------------------------------------------------------
6318   struct IDSourceIterator : public SMDS_ElemIterator
6319   {
6320     const SMESH::smIdType*        _idPtr;
6321     const SMESH::smIdType*        _idEndPtr;
6322     SMESH::smIdType_array_var     _idArray;
6323     const SMDS_Mesh*              _mesh;
6324     const SMDSAbs_ElementType     _type;
6325     const SMDS_MeshElement*       _elem;
6326
6327     IDSourceIterator( const SMDS_Mesh*       mesh,
6328                       const SMESH::smIdType* ids,
6329                       const smIdType         nbIds,
6330                       SMDSAbs_ElementType    type):
6331       _idPtr( ids ), _idEndPtr( ids + nbIds ), _mesh( mesh ), _type( type ), _elem( 0 )
6332     {
6333       if ( _idPtr && nbIds && _mesh )
6334         next();
6335     }
6336     IDSourceIterator( const SMDS_Mesh*       mesh,
6337                       SMESH::smIdType_array* idArray,
6338                       SMDSAbs_ElementType    type):
6339       _idPtr( 0 ), _idEndPtr( 0 ), _idArray( idArray), _mesh( mesh ), _type( type ), _elem( 0 )
6340     {
6341       if ( idArray && _mesh )
6342       {
6343         _idPtr    = &_idArray[0];
6344         _idEndPtr = _idPtr + _idArray->length();
6345         next();
6346       }
6347     }
6348     virtual bool more()
6349     {
6350       return _elem;
6351     }
6352     virtual const SMDS_MeshElement* next()
6353     {
6354       const SMDS_MeshElement* res = _elem;
6355       _elem = 0;
6356       while ( _idPtr < _idEndPtr && !_elem )
6357       {
6358         if ( _type == SMDSAbs_Node )
6359         {
6360           _elem = _mesh->FindNode( *_idPtr++ );
6361         }
6362         else if ((_elem = _mesh->FindElement( *_idPtr++ )) &&
6363                  (_elem->GetType() != _type && _type != SMDSAbs_All ))
6364         {
6365           _elem = 0;
6366         }
6367       }
6368       return res;
6369     }
6370   };
6371   //-----------------------------------------------------------------------------
6372
6373   struct NodeOfElemIterator : public SMDS_ElemIterator
6374   {
6375     TColStd_MapOfInteger    _checkedNodeIDs;
6376     SMDS_ElemIteratorPtr    _elemIter;
6377     SMDS_ElemIteratorPtr    _nodeIter;
6378     const SMDS_MeshElement* _node;
6379
6380     NodeOfElemIterator( SMDS_ElemIteratorPtr iter ): _elemIter( iter ), _node( 0 )
6381     {
6382       if ( _elemIter && _elemIter->more() )
6383       {
6384         _nodeIter = _elemIter->next()->nodesIterator();
6385         next();
6386       }
6387     }
6388     virtual bool more()
6389     {
6390       return _node;
6391     }
6392     virtual const SMDS_MeshElement* next()
6393     {
6394       const SMDS_MeshElement* res = _node;
6395       _node = 0;
6396       while ( !_node && ( _elemIter->more() || _nodeIter->more() ))
6397       {
6398         if ( _nodeIter->more() )
6399         {
6400           _node = _nodeIter->next();
6401           if ( !_checkedNodeIDs.Add( _node->GetID() ))
6402             _node = 0;
6403         }
6404         else
6405         {
6406           _nodeIter = _elemIter->next()->nodesIterator();
6407         }
6408       }
6409       return res;
6410     }
6411   };
6412 }
6413
6414 //=============================================================================
6415 /*
6416  * Return iterator on elements of given type in given object
6417  */
6418 //=============================================================================
6419
6420 SMDS_ElemIteratorPtr SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_ptr theObject,
6421                                                SMESH::ElementType        theType)
6422 {
6423   SMDS_ElemIteratorPtr  elemIt;
6424   bool                  typeOK = ( theType == SMESH::ALL );
6425   SMDSAbs_ElementType elemType = SMDSAbs_ElementType( theType );
6426
6427   SMESH::SMESH_Mesh_var meshVar = theObject->GetMesh();
6428   SMESH_Mesh_i*          mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( meshVar );
6429   if ( !mesh_i ) return elemIt;
6430   SMESHDS_Mesh*          meshDS = mesh_i->GetImpl().GetMeshDS();
6431
6432   if ( SMESH::DownCast<SMESH_Mesh_i*>( theObject ))
6433   {
6434     elemIt = meshDS->elementsIterator( elemType );
6435     typeOK = true;
6436   }
6437   else if ( SMESH_subMesh_i* submesh_i = SMESH::DownCast<SMESH_subMesh_i*>( theObject ))
6438   {
6439     SMESHDS_SubMesh* sm = ((SMESHDS_Mesh*) meshDS)->MeshElements( submesh_i->GetId() );
6440     if ( sm )
6441     {
6442       elemIt = sm->GetElements();
6443       if ( elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
6444       {
6445         typeOK = ( elemIt && elemIt->more() && elemIt->next()->GetType() == elemType );
6446         elemIt = typeOK ? sm->GetElements() : SMDS_ElemIteratorPtr();
6447       }
6448     }
6449   }
6450   else if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( theObject ))
6451   {
6452     SMESHDS_GroupBase* groupDS = group_i->GetGroupDS();
6453     if ( groupDS && ( elemType == groupDS->GetType()  ||
6454                       elemType == SMDSAbs_Node ||
6455                       elemType == SMDSAbs_All ))
6456     {
6457       elemIt = groupDS->GetElements();
6458       typeOK = ( groupDS->GetType() == elemType || elemType == SMDSAbs_All );
6459     }
6460   }
6461   else if ( SMESH::Filter_i* filter_i = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
6462   {
6463     if ( filter_i->GetElementType() == theType ||
6464          filter_i->GetElementType() == SMESH::ALL ||
6465          elemType == SMDSAbs_Node ||
6466          elemType == SMDSAbs_All)
6467     {
6468       SMESH::Predicate_i* pred_i = filter_i->GetPredicate_i();
6469       if ( pred_i && pred_i->GetPredicate() )
6470       {
6471         SMDSAbs_ElementType filterType = SMDSAbs_ElementType( filter_i->GetElementType() );
6472         SMDS_ElemIteratorPtr allElemIt = meshDS->elementsIterator( filterType );
6473         SMDSAbs_ElementType   iterType = elemType == SMDSAbs_Node ? filterType : elemType;
6474         elemIt = SMDS_ElemIteratorPtr
6475           ( new PredicateIterator( allElemIt, pred_i->GetPredicate(), iterType ));
6476         typeOK = ( elemType == SMDSAbs_Node ? filterType == SMDSAbs_Node : elemIt->more() );
6477       }
6478     }
6479   }
6480   else
6481   {
6482     SMESH::array_of_ElementType_var types = theObject->GetTypes();
6483     const bool                    isNodes = ( types->length() == 1 && types[0] == SMESH::NODE );
6484     if ( isNodes && elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
6485       return elemIt;
6486     SMDSAbs_ElementType iterType = isNodes ? SMDSAbs_Node : elemType;
6487     if ( SMESH_MeshEditor_i::IsTemporaryIDSource( theObject ))
6488     {
6489       SMESH::smIdType nbIds;
6490       if ( SMESH::smIdType* ids = SMESH_MeshEditor_i::GetTemporaryIDs( theObject, nbIds ))
6491         elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids, nbIds, iterType ));
6492     }
6493     else
6494     {
6495       SMESH::smIdType_array_var ids = theObject->GetIDs();
6496       elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids._retn(), iterType ));
6497     }
6498     typeOK = ( isNodes == ( elemType == SMDSAbs_Node )) || ( elemType == SMDSAbs_All );
6499   }
6500
6501   if ( elemIt && elemIt->more() && !typeOK )
6502   {
6503     if ( elemType == SMDSAbs_Node )
6504     {
6505       elemIt = SMDS_ElemIteratorPtr( new NodeOfElemIterator( elemIt ));
6506     }
6507     else
6508     {
6509       elemIt = SMDS_ElemIteratorPtr();
6510     }
6511   }
6512   return elemIt;
6513 }
6514
6515 //=============================================================================
6516 namespace // Finding concurrent hypotheses
6517 //=============================================================================
6518 {
6519
6520 /*!
6521  * \brief mapping of mesh dimension into shape type
6522  */
6523 TopAbs_ShapeEnum shapeTypeByDim(const int theDim)
6524 {
6525   TopAbs_ShapeEnum aType = TopAbs_SOLID;
6526   switch ( theDim ) {
6527   case 0: aType = TopAbs_VERTEX; break;
6528   case 1: aType = TopAbs_EDGE; break;
6529   case 2: aType = TopAbs_FACE; break;
6530   case 3:
6531   default:aType = TopAbs_SOLID; break;
6532   }
6533   return aType;
6534 }
6535
6536 //-----------------------------------------------------------------------------
6537 /*!
6538  * \brief Internal structure used to find concurrent submeshes
6539  *
6540  * It represents a pair < submesh, concurrent dimension >, where
6541  * 'concurrent dimension' is dimension of shape where the submesh can concurrent
6542  *  with another submesh. In other words, it is dimension of a hypothesis assigned
6543  *  to submesh.
6544  */
6545 class SMESH_DimHyp
6546 {
6547  public:
6548   //! fields
6549   int _dim;    //!< a dimension the algo can build (concurrent dimension)
6550   int _ownDim; //!< dimension of shape of _subMesh (>=_dim)
6551   TopTools_MapOfShape  _shapeMap; //!< [sub-]shapes of dimension == _dim
6552   const SMESH_subMesh* _subMesh;
6553   list<const SMESHDS_Hypothesis*> _hypotheses; //!< algo is first, then its parameters
6554
6555   //-----------------------------------------------------------------------------
6556   // Return the algorithm
6557   const SMESH_Algo* GetAlgo() const
6558   { return _hypotheses.empty() ? 0 : dynamic_cast<const SMESH_Algo*>( _hypotheses.front() ); }
6559
6560   //-----------------------------------------------------------------------------
6561   //! Constructors
6562   SMESH_DimHyp(const SMESH_subMesh* theSubMesh,
6563                const int            theDim,
6564                const TopoDS_Shape&  theShape)
6565   {
6566     _subMesh = theSubMesh;
6567     SetShape( theDim, theShape );
6568   }
6569
6570   //-----------------------------------------------------------------------------
6571   //! set shape
6572   void SetShape(const int           theDim,
6573                 const TopoDS_Shape& theShape)
6574   {
6575     _dim = theDim;
6576     _ownDim = SMESH_Gen::GetShapeDim(theShape);
6577     if (_dim >= _ownDim)
6578       _shapeMap.Add( theShape );
6579     else {
6580       TopExp_Explorer anExp( theShape, shapeTypeByDim(theDim) );
6581       for( ; anExp.More(); anExp.Next() )
6582         _shapeMap.Add( anExp.Current() );
6583     }
6584   }
6585
6586   //-----------------------------------------------------------------------------
6587   //! Check sharing of sub-shapes
6588   static bool isShareSubShapes(const TopTools_MapOfShape& theToCheck,
6589                                const TopTools_MapOfShape& theToFind,
6590                                const TopAbs_ShapeEnum     theType)
6591   {
6592     bool isShared = false;
6593     TopTools_MapIteratorOfMapOfShape anItr( theToCheck );
6594     for (; !isShared && anItr.More(); anItr.Next() )
6595     {
6596       const TopoDS_Shape& aSubSh = anItr.Key();
6597       // check for case when concurrent dimensions are same
6598       isShared = theToFind.Contains( aSubSh );
6599       // check for sub-shape with concurrent dimension
6600       TopExp_Explorer anExp( aSubSh, theType );
6601       for ( ; !isShared && anExp.More(); anExp.Next() )
6602         isShared = theToFind.Contains( anExp.Current() );
6603     }
6604     return isShared;
6605   }
6606
6607   //-----------------------------------------------------------------------------
6608   //! check algorithms
6609   static bool checkAlgo(const SMESHDS_Hypothesis* theA1,
6610                         const SMESHDS_Hypothesis* theA2)
6611   {
6612     if ( !theA1 || !theA2 ||
6613          theA1->GetType() == SMESHDS_Hypothesis::PARAM_ALGO ||
6614          theA2->GetType() == SMESHDS_Hypothesis::PARAM_ALGO )
6615       return false; // one of the hypothesis is not algorithm
6616     // check algorithm names (should be equal)
6617     return strcmp( theA1->GetName(), theA2->GetName() ) == 0;
6618   }
6619
6620
6621   //-----------------------------------------------------------------------------
6622   //! Check if sub-shape hypotheses are concurrent
6623   bool IsConcurrent(const SMESH_DimHyp* theOther) const
6624   {
6625     if ( _subMesh == theOther->_subMesh )
6626       return false; // same sub-shape - should not be
6627
6628     // if ( <own dim of either of submeshes> == <concurrent dim> &&
6629     //      any of the two submeshes is not on COMPOUND shape )
6630     //  -> no concurrency
6631     bool meIsCompound    = (_subMesh->GetSubMeshDS() &&
6632                             _subMesh->GetSubMeshDS()->IsComplexSubmesh());
6633     bool otherIsCompound = (theOther->_subMesh->GetSubMeshDS() &&
6634                             theOther->_subMesh->GetSubMeshDS()->IsComplexSubmesh());
6635     if ( (_ownDim == _dim  || theOther->_ownDim == _dim ) && (!meIsCompound || !otherIsCompound))
6636       return false;
6637
6638     bool checkSubShape = isShareSubShapes( _shapeMap, theOther->_shapeMap, shapeTypeByDim(_dim));
6639     if ( !checkSubShape )
6640       return false;
6641
6642     // check algorithms to be same
6643     const SMESH_Algo* a1 = this->GetAlgo();
6644     const SMESH_Algo* a2 = theOther->GetAlgo();
6645     bool isSame = checkAlgo( a1, a2 );
6646     if ( !isSame )
6647     {
6648       return true;
6649       // commented off for IPAL54678
6650       // if ( !a1 || !a2 )
6651       //   return false; // pb?
6652       // return a1->GetDim() == a2->GetDim(); // different algorithms of same dim -> concurrency !
6653     }
6654
6655     // check hypothesises for concurrence (skip first as algorithm)
6656     size_t nbSame = 0;
6657     // pointers should be same, because it is referened from mesh hypothesis partition
6658     list <const SMESHDS_Hypothesis*>::const_iterator hypIt = _hypotheses.begin();
6659     list <const SMESHDS_Hypothesis*>::const_iterator otheEndIt = theOther->_hypotheses.end();
6660     for ( hypIt++ /*skip first as algo*/; hypIt != _hypotheses.end(); hypIt++ )
6661       if ( find( theOther->_hypotheses.begin(), otheEndIt, *hypIt ) != otheEndIt )
6662         nbSame++;
6663     // the submeshes are concurrent if their algorithms has different parameters
6664     return nbSame != theOther->_hypotheses.size() - 1;
6665   }
6666
6667   // Return true if algorithm of this SMESH_DimHyp is used if no
6668   // sub-mesh order is imposed by the user
6669   bool IsHigherPriorityThan( const SMESH_DimHyp* theOther ) const
6670   {
6671     // NeedDiscreteBoundary() algo has a higher priority
6672     if ( this    ->GetAlgo()->NeedDiscreteBoundary() !=
6673          theOther->GetAlgo()->NeedDiscreteBoundary() )
6674       return !this->GetAlgo()->NeedDiscreteBoundary();
6675
6676     return ( this->_subMesh->GetId() < theOther->_subMesh->GetId() );
6677   }
6678
6679 }; // end of SMESH_DimHyp
6680 //-----------------------------------------------------------------------------
6681
6682 typedef list<const SMESH_DimHyp*> TDimHypList;
6683
6684 //-----------------------------------------------------------------------------
6685
6686 void addDimHypInstance(const int                               theDim,
6687                        const TopoDS_Shape&                     theShape,
6688                        const SMESH_Algo*                       theAlgo,
6689                        const SMESH_subMesh*                    theSubMesh,
6690                        const list <const SMESHDS_Hypothesis*>& theHypList,
6691                        TDimHypList*                            theDimHypListArr )
6692 {
6693   if ( !theAlgo->NeedDiscreteBoundary() &&
6694        theAlgo->NeedLowerHyps( theDim )) // IPAL54678
6695     return;
6696   TDimHypList& listOfdimHyp = theDimHypListArr[theDim];
6697   if ( listOfdimHyp.empty() || listOfdimHyp.back()->_subMesh != theSubMesh )
6698   {
6699     SMESH_DimHyp* dimHyp = new SMESH_DimHyp( theSubMesh, theDim, theShape );
6700     dimHyp->_hypotheses.push_front(theAlgo);
6701     listOfdimHyp.push_back( dimHyp );
6702   }
6703
6704   SMESH_DimHyp* dimHyp = const_cast<SMESH_DimHyp*>( listOfdimHyp.back() );
6705   dimHyp->_hypotheses.insert( dimHyp->_hypotheses.end(),
6706                               theHypList.begin(), theHypList.end() );
6707 }
6708
6709 //-----------------------------------------------------------------------------
6710 void addInOrderOfPriority( const SMESH_DimHyp* theDimHyp,
6711                            TDimHypList&        theListOfConcurr)
6712 {
6713   if ( theListOfConcurr.empty() )
6714   {
6715     theListOfConcurr.push_back( theDimHyp );
6716   }
6717   else
6718   {
6719     TDimHypList::iterator hypIt = theListOfConcurr.begin();
6720     while ( hypIt != theListOfConcurr.end() &&
6721             !theDimHyp->IsHigherPriorityThan( *hypIt ))
6722       ++hypIt;
6723     theListOfConcurr.insert( hypIt, theDimHyp );
6724   }
6725 }
6726
6727 //-----------------------------------------------------------------------------
6728 void findConcurrents(const SMESH_DimHyp* theDimHyp,
6729                      const TDimHypList&  theListOfDimHyp,
6730                      TDimHypList&        theListOfConcurrHyp,
6731                      set<int>&           theSetOfConcurrId )
6732 {
6733   TDimHypList::const_reverse_iterator rIt = theListOfDimHyp.rbegin();
6734   for ( ; rIt != theListOfDimHyp.rend(); rIt++ )
6735   {
6736     const SMESH_DimHyp* curDimHyp = *rIt;
6737     if ( curDimHyp == theDimHyp )
6738       break; // meet own dimHyp pointer in same dimension
6739
6740     if ( theDimHyp->IsConcurrent( curDimHyp ) &&
6741          theSetOfConcurrId.insert( curDimHyp->_subMesh->GetId() ).second )
6742     {
6743       addInOrderOfPriority( curDimHyp, theListOfConcurrHyp );
6744     }
6745   }
6746 }
6747
6748 //-----------------------------------------------------------------------------
6749 bool unionLists(TListOfInt&       theListOfId,
6750                 TListOfListOfInt& theListOfListOfId,
6751                 const int         theIndx )
6752 {
6753   bool changed = false;
6754   if ( theListOfId.empty() )
6755     return changed;
6756   TListOfListOfInt::iterator it = theListOfListOfId.begin();
6757   for ( int i = 0; it != theListOfListOfId.end(); it++, i++ )
6758   {
6759     if ( i < theIndx )
6760       continue; //skip already treated lists
6761     // check if other list has any same submesh object
6762     TListOfInt& otherListOfId = *it;
6763     if ( find_first_of( theListOfId.begin(), theListOfId.end(),
6764                         otherListOfId.begin(), otherListOfId.end() ) == theListOfId.end() )
6765       continue;
6766
6767     // union two lists (from source into target)
6768     TListOfInt::iterator it2 = otherListOfId.begin();
6769     for ( ; it2 != otherListOfId.end(); it2++ ) {
6770       if ( find( theListOfId.begin(), theListOfId.end(), (*it2) ) == theListOfId.end() )
6771       {
6772         theListOfId.push_back(*it2);
6773         changed = true;
6774       }
6775     }
6776     // clear source list
6777     otherListOfId.clear();
6778   }
6779   return changed;
6780 }
6781 //-----------------------------------------------------------------------------
6782
6783 //! free memory allocated for dimension-hypothesis objects
6784 void removeDimHyps( TDimHypList* theArrOfList )
6785 {
6786   for (int i = 0; i < 4; i++ ) {
6787     TDimHypList& listOfdimHyp = theArrOfList[i];
6788     TDimHypList::const_iterator it = listOfdimHyp.begin();
6789     for ( ; it != listOfdimHyp.end(); it++ )
6790       delete (*it);
6791   }
6792 }
6793
6794 //-----------------------------------------------------------------------------
6795 /*!
6796  * \brief find common submeshes with given submesh
6797  * \param theSubMeshList list of already collected submesh to check
6798  * \param theSubMesh given submesh to intersect with other
6799  * \param theCommonSubMeshes collected common submeshes
6800  */
6801 void findCommonSubMesh (list<const SMESH_subMesh*>& theSubMeshList,
6802                         const SMESH_subMesh*        theSubMesh,
6803                         set<const SMESH_subMesh*>&  theCommon )
6804 {
6805   if ( !theSubMesh )
6806     return;
6807   list<const SMESH_subMesh*>::const_iterator it = theSubMeshList.begin();
6808   for ( ; it != theSubMeshList.end(); it++ )
6809     theSubMesh->FindIntersection( *it, theCommon );
6810   theSubMeshList.push_back( theSubMesh );
6811   //theCommon.insert( theSubMesh );
6812 }
6813
6814 //-----------------------------------------------------------------------------
6815 bool isSubMeshInList ( int smID, const TListOfListOfInt& smLists )
6816 {
6817   TListOfListOfInt::const_iterator listsIt = smLists.begin();
6818   for ( ; listsIt != smLists.end(); ++listsIt )
6819   {
6820     const TListOfInt& smIDs = *listsIt;
6821     if ( std::find( smIDs.begin(), smIDs.end(), smID ) != smIDs.end() )
6822       return true;
6823   }
6824   return false;
6825 }
6826
6827 } // namespace
6828
6829 //=============================================================================
6830 /*!
6831  * \brief Return \c true if a meshing order not yet set for a concurrent sub-mesh
6832  */
6833 //=============================================================================
6834
6835 CORBA::Boolean SMESH_Mesh_i::IsUnorderedSubMesh(CORBA::Long submeshID)
6836 {
6837   TListOfListOfInt anOrder = GetImpl().GetMeshOrder(); // already defined order
6838   if ( isSubMeshInList( submeshID, anOrder ))
6839     return false;
6840
6841   TListOfListOfInt allConurrent = findConcurrentSubMeshes();
6842   return isSubMeshInList( submeshID, allConurrent );
6843 }
6844
6845 //=============================================================================
6846 /*!
6847  * \brief Return sub-mesh objects list in meshing order
6848  */
6849 //=============================================================================
6850
6851 SMESH::submesh_array_array* SMESH_Mesh_i::GetMeshOrder()
6852 {
6853   SMESH::submesh_array_array_var aResult = new SMESH::submesh_array_array();
6854
6855   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
6856   if ( !aMeshDS )
6857     return aResult._retn();
6858
6859   TListOfListOfInt      anOrder = GetImpl().GetMeshOrder(); // already defined order
6860   TListOfListOfInt allConurrent = findConcurrentSubMeshes();
6861   anOrder.splice( anOrder.end(), allConurrent );
6862
6863   bool changed;
6864   do {
6865     changed = false;
6866     TListOfListOfInt::iterator listIt = anOrder.begin();
6867     for ( int listIndx = 1; listIt != anOrder.end(); listIt++, listIndx++ )
6868       if ( unionLists( *listIt,  anOrder, listIndx ))
6869         changed = true;
6870   }
6871   while ( changed );
6872
6873   // convert submesh ids into interface instances
6874   //  and dump command into python
6875   convertMeshOrder( anOrder, aResult, false );
6876
6877   return aResult._retn();
6878 }
6879
6880 //=============================================================================
6881 /*!
6882  * \brief Finds concurrent sub-meshes
6883  */
6884 //=============================================================================
6885
6886 TListOfListOfInt SMESH_Mesh_i::findConcurrentSubMeshes()
6887 {
6888   TListOfListOfInt anOrder;
6889   ::SMESH_Mesh& mesh = GetImpl();
6890
6891   // collect submeshes and detect concurrent algorithms and hypothesises
6892   TDimHypList dimHypListArr[4]; // dimHyp list for each shape dimension
6893
6894   map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
6895   for ( ; i_sm != _mapSubMesh.end(); i_sm++ )
6896   {
6897     ::SMESH_subMesh* sm = (*i_sm).second;
6898     // shape of submesh
6899     const TopoDS_Shape& aSubMeshShape = sm->GetSubShape();
6900
6901     // list of assigned hypothesises
6902     const list <const SMESHDS_Hypothesis*>& hypList = mesh.GetHypothesisList(aSubMeshShape);
6903     // Find out dimensions where the submesh can be concurrent.
6904     // We define the dimensions by algo of each of hypotheses in hypList
6905     list <const SMESHDS_Hypothesis*>::const_iterator hypIt = hypList.begin();
6906     for( ; hypIt != hypList.end(); hypIt++ )
6907     {
6908       SMESH_Algo* anAlgo = 0;
6909       const SMESH_Hypothesis* hyp = dynamic_cast<const SMESH_Hypothesis*>(*hypIt);
6910       if ( hyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO )
6911         // hyp it-self is algo
6912         anAlgo = (SMESH_Algo*)dynamic_cast<const SMESH_Algo*>(hyp);
6913       else {
6914         // try to find algorithm with help of sub-shapes
6915         TopExp_Explorer anExp( aSubMeshShape, shapeTypeByDim(hyp->GetDim()) );
6916         for ( ; !anAlgo && anExp.More(); anExp.Next() )
6917           anAlgo = mesh.GetGen()->GetAlgo( mesh, anExp.Current() );
6918       }
6919       if (!anAlgo)
6920         continue; // no algorithm assigned to a current submesh
6921
6922       int dim = anAlgo->GetDim(); // top concurrent dimension (see comment to SMESH_DimHyp)
6923       // the submesh can concurrent at <dim> (or lower dims if !anAlgo->NeedDiscreteBoundary()
6924       // and !anAlgo->NeedLowerHyps( dim ))
6925
6926       // create instance of dimension-hypothesis for found concurrent dimension(s) and algorithm
6927       for ( int j = anAlgo->NeedDiscreteBoundary() ? dim : 1, jn = dim; j <= jn; j++ )
6928         addDimHypInstance( j, aSubMeshShape, anAlgo, sm, hypList, dimHypListArr );
6929     }
6930   } // end iterations on submesh
6931
6932     // iterate on created dimension-hypotheses and check for concurrents
6933   for ( int i = 0; i < 4; i++ )
6934   {
6935     const TDimHypList& listOfDimHyp = dimHypListArr[i];
6936     // check for concurrents in own and other dimensions (step-by-step)
6937     TDimHypList::const_iterator dhIt = listOfDimHyp.begin();
6938     for ( ; dhIt != listOfDimHyp.end(); dhIt++ )
6939     {
6940       const SMESH_DimHyp* dimHyp = *dhIt;
6941       TDimHypList listOfConcurr;
6942       set<int>    setOfConcurrIds;
6943       // looking for concurrents and collect into own list
6944       for ( int j = i; j < 4; j++ )
6945         findConcurrents( dimHyp, dimHypListArr[j], listOfConcurr, setOfConcurrIds );
6946       // check if any concurrents found
6947       if ( listOfConcurr.size() > 0 )
6948       {
6949         // add own submesh to list of concurrent
6950         addInOrderOfPriority( dimHyp, listOfConcurr );
6951         list<int> listOfConcurrIds;
6952         TDimHypList::iterator hypIt = listOfConcurr.begin();
6953         for ( ; hypIt != listOfConcurr.end(); ++hypIt )
6954           listOfConcurrIds.push_back( (*hypIt)->_subMesh->GetId() );
6955         anOrder.push_back( listOfConcurrIds );
6956       }
6957     }
6958   }
6959
6960   removeDimHyps(dimHypListArr);
6961
6962   // now, minimize the number of concurrent groups
6963   // Here we assume that lists of submeshes can have same submesh
6964   // in case of multi-dimension algorithms, as result
6965   //  list with common submesh has to be united into one list
6966   int listIndx = 0;
6967   TListOfListOfInt::iterator listIt = anOrder.begin();
6968   for(; listIt != anOrder.end(); listIt++, listIndx++ )
6969     unionLists( *listIt,  anOrder, listIndx + 1 );
6970
6971   return anOrder;
6972 }
6973
6974 //=============================================================================
6975 /*!
6976  * \brief Set submesh object order
6977  * \param theSubMeshArray submesh array order
6978  */
6979 //=============================================================================
6980
6981 ::CORBA::Boolean SMESH_Mesh_i::SetMeshOrder(const SMESH::submesh_array_array& theSubMeshArray)
6982 {
6983   if ( _preMeshInfo )
6984     _preMeshInfo->ForgetOrLoad();
6985
6986   bool res = false;
6987   ::SMESH_Mesh& mesh = GetImpl();
6988
6989   TPythonDump aPythonDump; // prevent dump of called methods
6990   aPythonDump << "isDone = " << SMESH::SMESH_Mesh_var(_this()) << ".SetMeshOrder( [ ";
6991
6992   TListOfListOfInt subMeshOrder;
6993   for ( int i = 0, n = theSubMeshArray.length(); i < n; i++ )
6994   {
6995     const SMESH::submesh_array& aSMArray = theSubMeshArray[i];
6996     TListOfInt subMeshIds;
6997     if ( i > 0 )
6998       aPythonDump << ", ";
6999     aPythonDump << "[ ";
7000     // Collect subMeshes which should be clear
7001     //  do it list-by-list, because modification of submesh order
7002     //  take effect between concurrent submeshes only
7003     set<const SMESH_subMesh*> subMeshToClear;
7004     list<const SMESH_subMesh*> subMeshList;
7005     for ( int j = 0, jn = aSMArray.length(); j < jn; j++ )
7006     {
7007       const SMESH::SMESH_subMesh_var subMesh = SMESH::SMESH_subMesh::_duplicate(aSMArray[j]);
7008       if ( j > 0 )
7009         aPythonDump << ", ";
7010       aPythonDump << subMesh;
7011       subMeshIds.push_back( subMesh->GetId() );
7012       // detect common parts of submeshes
7013       if ( _mapSubMesh.find(subMesh->GetId()) != _mapSubMesh.end() )
7014         findCommonSubMesh( subMeshList, _mapSubMesh[ subMesh->GetId() ], subMeshToClear );
7015     }
7016     aPythonDump << " ]";
7017     subMeshOrder.push_back( subMeshIds );
7018
7019     // clear collected sub-meshes
7020     set<const SMESH_subMesh*>::iterator clrIt = subMeshToClear.begin();
7021     for ( ; clrIt != subMeshToClear.end(); clrIt++ )
7022       if ( SMESH_subMesh* sm = (SMESH_subMesh*)*clrIt )
7023       {
7024         sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
7025         if ( SMESH_Algo* algo = sm->GetAlgo() ) // #16748
7026           sm->AlgoStateEngine( SMESH_subMesh::MODIF_HYP, algo ); // to clear a cached algo
7027       }
7028   }
7029   aPythonDump << " ])";
7030
7031   mesh.SetMeshOrder( subMeshOrder );
7032   res = true;
7033
7034   SMESH::SMESH_Mesh_var me = _this();
7035   _gen_i->UpdateIcons( me );
7036
7037   return res;
7038 }
7039
7040 //=============================================================================
7041 /*!
7042  * \brief Convert submesh ids into submesh interfaces
7043  */
7044 //=============================================================================
7045
7046 void SMESH_Mesh_i::convertMeshOrder (const TListOfListOfInt&     theIdsOrder,
7047                                      SMESH::submesh_array_array& theResOrder,
7048                                      const bool                  theIsDump)
7049 {
7050   int nbSet = theIdsOrder.size();
7051   TPythonDump aPythonDump; // prevent dump of called methods
7052   if ( theIsDump )
7053     aPythonDump << "[ ";
7054   theResOrder.length(nbSet);
7055   TListOfListOfInt::const_iterator it = theIdsOrder.begin();
7056   int listIndx = 0;
7057   for( ; it != theIdsOrder.end(); it++ )
7058   {
7059     // translate submesh identificators into submesh objects
7060     //  takeing into account real number of concurrent lists
7061     const TListOfInt& aSubOrder = (*it);
7062     if (!aSubOrder.size())
7063       continue;
7064     if ( theIsDump )
7065       aPythonDump << "[ ";
7066     // convert shape indices into interfaces
7067     SMESH::submesh_array_var aResSubSet = new SMESH::submesh_array();
7068     aResSubSet->length(aSubOrder.size());
7069     TListOfInt::const_iterator subIt = aSubOrder.begin();
7070     int j;
7071     for( j = 0; subIt != aSubOrder.end(); subIt++ )
7072     {
7073       if ( _mapSubMeshIor.find(*subIt) == _mapSubMeshIor.end() )
7074         continue;
7075       SMESH::SMESH_subMesh_var subMesh =
7076         SMESH::SMESH_subMesh::_duplicate( _mapSubMeshIor[*subIt] );
7077       if ( theIsDump ) {
7078         if ( j > 0 )
7079           aPythonDump << ", ";
7080         aPythonDump << subMesh;
7081       }
7082       aResSubSet[ j++ ] = subMesh;
7083     }
7084     if ( theIsDump )
7085       aPythonDump << " ]";
7086     if ( j > 1 )
7087       theResOrder[ listIndx++ ] = aResSubSet;
7088   }
7089   // correct number of lists
7090   theResOrder.length( listIndx );
7091
7092   if ( theIsDump ) {
7093     // finilise python dump
7094     aPythonDump << " ]";
7095     aPythonDump << " = " << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshOrder()";
7096   }
7097 }
7098
7099 namespace // utils used by SMESH_MeshPartDS
7100 {
7101   /*!
7102    * \brief Class used to access to protected data of SMDS_MeshInfo
7103    */
7104   struct TMeshInfo : public SMDS_MeshInfo
7105   {
7106     void Add(const SMDS_MeshElement* e) { SMDS_MeshInfo::addWithPoly( e ); }
7107   };
7108   /*!
7109    * \brief Element holing its ID only
7110    */
7111   struct TElemID : public SMDS_LinearEdge
7112   {
7113     TElemID(int ID) : SMDS_LinearEdge(0,0) { setID( ID ); }
7114   };
7115 }
7116
7117 //================================================================================
7118 //
7119 // Implementation of SMESH_MeshPartDS
7120 //
7121 SMESH_MeshPartDS::SMESH_MeshPartDS(SMESH::SMESH_IDSource_ptr meshPart):
7122   SMESHDS_Mesh( /*meshID=*/-1, /*isEmbeddedMode=*/true)
7123 {
7124   SMESH::SMESH_Mesh_var mesh = meshPart->GetMesh();
7125   SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
7126
7127   mesh_i->Load();
7128   _meshDS = mesh_i->GetImpl().GetMeshDS();
7129
7130   SetPersistentId( _meshDS->GetPersistentId() );
7131
7132   if ( mesh_i == SMESH::DownCast<SMESH_Mesh_i*>( meshPart ))
7133   {
7134     // <meshPart> is the whole mesh
7135     myInfo = _meshDS->GetMeshInfo(); // copy mesh info;
7136     // copy groups
7137     set<SMESHDS_GroupBase*>& myGroupSet = const_cast<set<SMESHDS_GroupBase*>&>( GetGroups() );
7138     myGroupSet = _meshDS->GetGroups();
7139   }
7140   else
7141   {
7142     TMeshInfo tmpInfo;
7143     SMESH::smIdType_array_var       anIDs = meshPart->GetIDs();
7144     SMESH::array_of_ElementType_var types = meshPart->GetTypes();
7145     if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
7146     {
7147       for ( CORBA::ULong i=0; i < anIDs->length(); i++ )
7148         if ( const SMDS_MeshNode * n = _meshDS->FindNode( anIDs[i] ))
7149           if ( _elements[ SMDSAbs_Node ].insert( n ).second )
7150             tmpInfo.Add( n );
7151     }
7152     else
7153     {
7154       for ( CORBA::ULong i=0; i < anIDs->length(); i++ )
7155         if ( const SMDS_MeshElement * e = _meshDS->FindElement(anIDs[i]))
7156           if ( _elements[ e->GetType() ].insert( e ).second )
7157           {
7158             tmpInfo.Add( e );
7159             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7160             while ( nIt->more() )
7161             {
7162               const SMDS_MeshNode * n = (const SMDS_MeshNode*) nIt->next();
7163               if ( _elements[ SMDSAbs_Node ].insert( n ).second )
7164                 tmpInfo.Add( n );
7165             }
7166           }
7167     }
7168     myInfo = tmpInfo;
7169
7170     ShapeToMesh( _meshDS->ShapeToMesh() );
7171
7172     _meshDS = 0; // to enforce iteration on _elements and _nodes
7173   }
7174 }
7175 // -------------------------------------------------------------------------------------
7176 SMESH_MeshPartDS::SMESH_MeshPartDS(const std::list< const SMDS_MeshElement* > & meshPart):
7177   SMESHDS_Mesh( /*meshID=*/-1, /*isEmbeddedMode=*/true), _meshDS(0)
7178 {
7179   TMeshInfo tmpInfo;
7180   list< const SMDS_MeshElement* >::const_iterator partIt = meshPart.begin();
7181   for ( ; partIt != meshPart.end(); ++partIt )
7182     if ( const SMDS_MeshElement * e = *partIt )
7183       if ( _elements[ e->GetType() ].insert( e ).second )
7184       {
7185         tmpInfo.Add( e );
7186         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7187         while ( nIt->more() )
7188         {
7189           const SMDS_MeshNode * n = (const SMDS_MeshNode*) nIt->next();
7190           if ( _elements[ SMDSAbs_Node ].insert( n ).second )
7191             tmpInfo.Add( n );
7192         }
7193       }
7194   myInfo = tmpInfo;
7195 }
7196 // -------------------------------------------------------------------------------------
7197 const SMDS_MeshElement * SMESH_MeshPartDS::FindElement(int IDelem) const
7198 {
7199   if ( _meshDS ) return _meshDS->FindElement( IDelem );
7200
7201   TElemID elem( IDelem );
7202   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
7203     if ( !_elements[ iType ].empty() )
7204     {
7205       TIDSortedElemSet::const_iterator it = _elements[ iType ].find( &elem );
7206       if ( it != _elements[ iType ].end() )
7207         return *it;
7208     }
7209   return 0;
7210 }
7211 // -------------------------------------------------------------------------------------
7212 bool SMESH_MeshPartDS::HasNumerationHoles()
7213 {
7214   if ( _meshDS ) return _meshDS->HasNumerationHoles();
7215
7216   return ( MinNodeID() != 1 ||
7217            MaxNodeID() != NbNodes() ||
7218            MinElementID() != 1 ||
7219            MaxElementID() != NbElements() );
7220 }
7221 // -------------------------------------------------------------------------------------
7222 smIdType SMESH_MeshPartDS::MaxNodeID() const
7223 {
7224   if ( _meshDS ) return _meshDS->MaxNodeID();
7225   return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].rbegin())->GetID();
7226 }
7227 // -------------------------------------------------------------------------------------
7228 smIdType SMESH_MeshPartDS::MinNodeID() const
7229 {
7230   if ( _meshDS ) return _meshDS->MinNodeID();
7231   return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].begin())->GetID();
7232 }  
7233 // -------------------------------------------------------------------------------------
7234 smIdType SMESH_MeshPartDS::MaxElementID() const
7235 {
7236   if ( _meshDS ) return _meshDS->MaxElementID();
7237   smIdType maxID = 0;
7238   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
7239     if ( !_elements[ iType ].empty() )
7240       maxID = std::max( maxID, (*_elements[ iType ].rbegin())->GetID() );
7241   return maxID;
7242 }
7243 // -------------------------------------------------------------------------------------
7244 smIdType SMESH_MeshPartDS::MinElementID() const
7245 {
7246   if ( _meshDS ) return _meshDS->MinElementID();
7247   smIdType minID = 0;
7248   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
7249     if ( !_elements[ iType ].empty() )
7250       minID = std::min( minID, (*_elements[ iType ].begin())->GetID() );
7251   return minID;
7252 }
7253 // -------------------------------------------------------------------------------------
7254 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementGeomIterator(SMDSAbs_GeometryType geomType) const
7255 {
7256   if ( _meshDS ) return _meshDS->elementGeomIterator( geomType );
7257
7258   typedef SMDS_SetIterator
7259     <const SMDS_MeshElement*,
7260     TIDSortedElemSet::const_iterator,
7261     SMDS::SimpleAccessor<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator>,
7262     SMDS_MeshElement::GeomFilter
7263     > TIter;
7264
7265   SMDSAbs_ElementType type = SMDS_MeshCell::ElemType( geomType );
7266
7267   return SMDS_ElemIteratorPtr( new TIter( _elements[type].begin(),
7268                                           _elements[type].end(),
7269                                           SMDS_MeshElement::GeomFilter( geomType )));
7270 }
7271 // -------------------------------------------------------------------------------------
7272 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementEntityIterator(SMDSAbs_EntityType entity) const
7273 {
7274   if ( _meshDS ) return _meshDS->elementEntityIterator( entity );
7275
7276   typedef SMDS_SetIterator
7277     <const SMDS_MeshElement*,
7278     TIDSortedElemSet::const_iterator,
7279     SMDS::SimpleAccessor<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator>,
7280     SMDS_MeshElement::EntityFilter
7281     > TIter;
7282
7283   SMDSAbs_ElementType type = SMDS_MeshCell::ElemType( entity );
7284
7285   return SMDS_ElemIteratorPtr( new TIter( _elements[type].begin(),
7286                                           _elements[type].end(),
7287                                           SMDS_MeshElement::EntityFilter( entity )));
7288 }
7289 // -------------------------------------------------------------------------------------
7290 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementsIterator(SMDSAbs_ElementType type) const
7291 {
7292   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
7293   if ( type == SMDSAbs_All && !_meshDS )
7294   {
7295     typedef vector< SMDS_ElemIteratorPtr > TIterVec;
7296     TIterVec iterVec;
7297     for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
7298       if ( !_elements[i].empty() && i != SMDSAbs_Node )
7299         iterVec.push_back
7300           ( SMDS_ElemIteratorPtr( new TIter( _elements[i].begin(), _elements[i].end() )));
7301
7302     typedef SMDS_IteratorOnIterators<const SMDS_MeshElement*, TIterVec > TIterOnIters;
7303     return SMDS_ElemIteratorPtr( new TIterOnIters( iterVec ));
7304   }
7305   return _meshDS ? _meshDS->elementsIterator(type) : SMDS_ElemIteratorPtr
7306       ( new TIter( _elements[type].begin(), _elements[type].end() ));
7307 }
7308 // -------------------------------------------------------------------------------------
7309 #define _GET_ITER_DEFINE( iterType, methName, elem, elemType)                       \
7310   iterType SMESH_MeshPartDS::methName() const                 \
7311   {                                                                                 \
7312     typedef SMDS_SetIterator<const elem*, TIDSortedElemSet::const_iterator > TIter; \
7313     return _meshDS ? _meshDS->methName() : iterType                 \
7314       ( new TIter( _elements[elemType].begin(), _elements[elemType].end() ));       \
7315   }
7316 // -------------------------------------------------------------------------------------
7317 _GET_ITER_DEFINE( SMDS_NodeIteratorPtr, nodesIterator, SMDS_MeshNode, SMDSAbs_Node )
7318 _GET_ITER_DEFINE( SMDS_EdgeIteratorPtr, edgesIterator, SMDS_MeshEdge, SMDSAbs_Edge )
7319 _GET_ITER_DEFINE( SMDS_FaceIteratorPtr, facesIterator, SMDS_MeshFace, SMDSAbs_Face )
7320 _GET_ITER_DEFINE( SMDS_VolumeIteratorPtr, volumesIterator, SMDS_MeshVolume, SMDSAbs_Volume)
7321 #undef _GET_ITER_DEFINE
7322 //
7323 // END Implementation of SMESH_MeshPartDS
7324 //
7325 //================================================================================