Salome HOME
#24666 [CEA][Windows] BLSURPLUGIN compilation issue
[modules/smesh.git] / src / SMESH_I / SMESH_Mesh_i.cxx
1 // Copyright (C) 2007-2021  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  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       if ( nb != NbNodes() + NbElements() ) // something removed due to hypotheses change
2419         _gen_i->UpdateIcons( me );
2420       return;
2421     }
2422
2423   // Update after shape modification or breakLink w/o geometry change
2424
2425   GEOM_Client* geomClient = _gen_i->GetShapeReader();
2426   if ( !geomClient ) return;
2427   GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine( mainGO );
2428   if ( geomGen->_is_nil() ) return;
2429   CORBA::String_var geomComponentType = geomGen->ComponentDataType();
2430   bool isShaper = ( strcmp( geomComponentType.in(), "SHAPERSTUDY" ) == 0 );
2431
2432   SMESHDS_Mesh * meshDS = _impl->GetMeshDS();
2433
2434   TopoDS_Shape newShape = _gen_i->GeomObjectToShape( mainGO );
2435   if ( meshDS->ShapeToIndex( newShape ) == 1 ) // not yet updated
2436   {
2437     CORBA::String_var ior = geomGen->GetStringFromIOR( mainGO );
2438     geomClient->RemoveShapeFromBuffer( ior.in() );
2439     newShape = _gen_i->GeomObjectToShape( mainGO );
2440   }
2441
2442   // Update data taking into account that if topology doesn't change
2443   // all sub-shapes change but IDs of sub-shapes remain (except for geom groups)
2444
2445   if ( _preMeshInfo )
2446     _preMeshInfo->ForgetAllData();
2447
2448   if ( geomChanged || !isShaper )
2449     _impl->Clear();
2450   if ( newShape.IsNull() )
2451     return;
2452
2453   _mainShapeTick = mainGO->GetTick();
2454
2455   // store data of groups on geometry including new TopoDS_Shape's
2456   std::vector< TGroupOnGeomData > groupsData;
2457   const std::set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
2458   groupsData.reserve( groups.size() );
2459   TopTools_DataMapOfShapeShape old2newShapeMap;
2460   std::set<SMESHDS_GroupBase*>::const_iterator g = groups.begin();
2461   for ( ; g != groups.end(); ++g )
2462   {
2463     if ( const SMESHDS_GroupOnGeom* group = dynamic_cast< SMESHDS_GroupOnGeom* >( *g ))
2464     {
2465       groupsData.push_back( TGroupOnGeomData( group ));
2466
2467       // get a new shape
2468       SMESH::SMESH_GroupOnGeom_var gog;
2469       std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.find( group->GetID() );
2470       if ( i_grp != _mapGroups.end() )
2471         gog = SMESH::SMESH_GroupOnGeom::_narrow( i_grp->second );
2472
2473       GEOM::GEOM_Object_var geom;
2474       if ( !gog->_is_nil() )
2475       {
2476         if ( !theIsBreakLink )
2477           geom = gog->GetShape();
2478
2479         if ( theIsBreakLink || geom->_is_nil() )
2480         {
2481           SALOMEDS::SObject_wrap grpSO = _gen_i->ObjectToSObject( gog );
2482           SALOMEDS::SObject_wrap geomRefSO, geomSO;
2483           if ( !grpSO->_is_nil() &&
2484                grpSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
2485                geomRefSO->ReferencedObject( geomSO.inout() ))
2486           {
2487             CORBA::Object_var geomObj = _gen_i->SObjectToObject( geomSO );
2488             geom = GEOM::GEOM_Object::_narrow( geomObj );
2489           }
2490         }
2491       }
2492       if ( old2newShapeMap.IsBound( group->GetShape() ))
2493       {
2494         groupsData.back()._shape = old2newShapeMap( group->GetShape() );
2495       }
2496       else if ( !geom->_is_nil() )
2497       {
2498         groupsData.back()._shape = _gen_i->GeomObjectToShape( geom );
2499         if ( meshDS->IsGroupOfSubShapes( groupsData.back()._shape ))
2500         {
2501           CORBA::String_var ior = geomGen->GetStringFromIOR( geom );
2502           geomClient->RemoveShapeFromBuffer( ior.in() );
2503           groupsData.back()._shape = _gen_i->GeomObjectToShape( geom );
2504         }
2505         old2newShapeMap.Bind( group->GetShape(), groupsData.back()._shape );
2506       }
2507       
2508     }
2509   }
2510   // store assigned hypotheses
2511   std::vector< pair< int, THypList > > ids2Hyps;
2512   const ShapeToHypothesis & hyps = meshDS->GetHypotheses();
2513   for ( ShapeToHypothesis::Iterator s2hyps( hyps ); s2hyps.More(); s2hyps.Next() )
2514   {
2515     const TopoDS_Shape& s = s2hyps.Key();
2516     const THypList&  hyps = s2hyps.ChangeValue();
2517     ids2Hyps.push_back( make_pair( meshDS->ShapeToIndex( s ), hyps ));
2518   }
2519
2520   std::multimap< std::set<int>, int > ii2iMap; // group sub-ids to group id in SMESHDS
2521
2522   // count shapes excluding compounds corresponding to geom groups
2523   int oldNbSubShapes = meshDS->MaxShapeIndex();
2524   for ( ; oldNbSubShapes > 0; --oldNbSubShapes )
2525   {
2526     const TopoDS_Shape& s = meshDS->IndexToShape( oldNbSubShapes );
2527     if ( s.IsNull() || s.ShapeType() != TopAbs_COMPOUND )
2528       break;
2529     // fill ii2iMap
2530     std::set<int> subIds;
2531     for ( TopoDS_Iterator it( s ); it.More(); it.Next() )
2532       subIds.insert( meshDS->ShapeToIndex( it.Value() ));
2533     ii2iMap.insert( std::make_pair( subIds, oldNbSubShapes ));
2534   }
2535
2536   // check if shape topology changes - save shape type per shape ID
2537   std::vector< TopAbs_ShapeEnum > shapeTypes( Max( oldNbSubShapes + 1, 1 ));
2538   for ( int shapeID = oldNbSubShapes; shapeID > 0; --shapeID )
2539     shapeTypes[ shapeID ] = meshDS->IndexToShape( shapeID ).ShapeType();
2540
2541   // change shape to mesh
2542   _impl->ShapeToMesh( TopoDS_Shape() );
2543   _impl->ShapeToMesh( newShape );
2544
2545   // check if shape topology changes - check new shape types
2546   bool sameTopology = ( oldNbSubShapes == meshDS->MaxShapeIndex() );
2547   for ( int shapeID = oldNbSubShapes; shapeID > 0 &&  sameTopology; --shapeID )
2548   {
2549     const TopoDS_Shape& s = meshDS->IndexToShape( shapeID );
2550     sameTopology = ( !s.IsNull() && s.ShapeType() == shapeTypes[ shapeID ]);
2551   }
2552
2553   // re-add shapes (compounds) of geom groups
2554   typedef std::map< std::vector< int >, TGeomGroupData* > TIndices2GroupData;
2555   TIndices2GroupData ii2grData;
2556   std::vector< int > ii;
2557   std::map< int, int > old2newIDs; // group IDs
2558   std::list<TGeomGroupData>::iterator dataIt = _geomGroupData.begin();
2559   for ( ; dataIt != _geomGroupData.end(); ++dataIt )
2560   {
2561     TGeomGroupData* data = &(*dataIt);
2562     ii.reserve( data->_indices.size() );
2563     ii.assign( data->_indices.begin(), data->_indices.end() );
2564     TIndices2GroupData::iterator ii2gd = ii2grData.insert( std::make_pair( ii, data )).first;
2565     if ( ii2gd->second != data )
2566     {
2567       data->_groupEntry = ii2gd->second->_groupEntry;
2568       data->_indices    = ii2gd->second->_indices;
2569       continue;
2570     }
2571     const int  oldNbSub = data->_indices.size();
2572     const int soleOldID = oldNbSub == 1 ? *data->_indices.begin() : 0;
2573     int oldID = 0;
2574     std::multimap< std::set<int>, int >::iterator ii2i = ii2iMap.find( data->_indices );
2575     if ( ii2i != ii2iMap.end() )
2576     {
2577       oldID = ii2i->second;
2578       ii2iMap.erase( ii2i );
2579     }
2580     if ( !oldID && oldNbSub == 1 )
2581       oldID = soleOldID;
2582     if ( old2newIDs.count( oldID ))
2583       continue;
2584
2585     int how = ( theIsBreakLink || !sameTopology ) ? IS_BREAK_LINK : MAIN_TRANSFORMED;
2586     newShape = newGroupShape( *data, how );
2587
2588     if ( !newShape.IsNull() )
2589     {
2590       if ( oldNbSub > 1 && meshDS->ShapeToIndex( newShape ) > 0 ) // group reduced to one sub-shape
2591       {
2592         TopoDS_Compound compound;
2593         BRep_Builder().MakeCompound( compound );
2594         BRep_Builder().Add( compound, newShape );
2595         newShape = compound;
2596       }
2597       int newID = _impl->GetSubMesh( newShape )->GetId();
2598       if ( oldID /*&& oldID != newID*/ )
2599         old2newIDs.insert( std::make_pair( oldID, newID ));
2600       if ( oldNbSub == 1 )
2601         old2newIDs.insert( std::make_pair( soleOldID, newID ));
2602     }
2603   }
2604
2605   // re-assign hypotheses
2606   for ( size_t i = 0; i < ids2Hyps.size(); ++i )
2607   {
2608     int sID = ids2Hyps[i].first;
2609     if ( sID != 1 )
2610     {
2611       std::map< int, int >::iterator o2n = old2newIDs.find( sID );
2612       if ( o2n != old2newIDs.end() )
2613         sID = o2n->second;
2614       else if ( !sameTopology )
2615         continue;
2616     }
2617     const TopoDS_Shape& s = meshDS->IndexToShape( sID );
2618     if ( s.IsNull() )
2619       continue;
2620     const THypList& hyps = ids2Hyps[i].second;
2621     THypList::const_iterator h = hyps.begin();
2622     for ( ; h != hyps.end(); ++h )
2623       _impl->AddHypothesis( s, (*h)->GetID() );
2624   }
2625
2626   {
2627     // restore groups on geometry
2628     for ( size_t i = 0; i < groupsData.size(); ++i )
2629     {
2630       const TGroupOnGeomData& data = groupsData[i];
2631       if ( data._shape.IsNull() )
2632         continue;
2633
2634       std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i2g = _mapGroups.find( data._oldID );
2635       if ( i2g == _mapGroups.end() ) continue;
2636
2637       SMESH_GroupBase_i* gr_i = SMESH::DownCast<SMESH_GroupBase_i*>( i2g->second );
2638       if ( !gr_i ) continue;
2639
2640       SMESH_Group* g = _impl->AddGroup( data._type, data._name.c_str(), data._oldID, data._shape );
2641       if ( !g )
2642         _mapGroups.erase( i2g );
2643       else
2644         g->GetGroupDS()->SetColor( data._color );
2645     }
2646
2647     if ( !sameTopology )
2648     {
2649       std::map< int, int >::iterator o2n = old2newIDs.begin();
2650       for ( ; o2n != old2newIDs.end(); ++o2n )
2651       {
2652         int newID = o2n->second, oldID = o2n->first;
2653         if ( newID == oldID || !_mapSubMesh.count( oldID ))
2654           continue;
2655         if ( newID > 0 )
2656         {
2657           _mapSubMesh   [ newID ] = _impl->GetSubMeshContaining( newID );
2658           _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2659           _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2660         }
2661         _mapSubMesh.   erase(oldID);
2662         _mapSubMesh_i. erase(oldID);
2663         _mapSubMeshIor.erase(oldID);
2664         if ( newID > 0 )
2665           _mapSubMesh_i [ newID ]->changeLocalId( newID );
2666       }
2667     }
2668
2669     // update _mapSubMesh
2670     std::map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
2671     for ( ; i_sm != _mapSubMesh.end(); ++i_sm )
2672       i_sm->second = _impl->GetSubMesh( meshDS->IndexToShape( i_sm->first ));
2673   }
2674
2675   if ( !sameTopology )
2676   {
2677     // remove invalid study sub-objects
2678     CheckGeomGroupModif();
2679   }
2680
2681   _gen_i->UpdateIcons( me );
2682
2683   if ( !theIsBreakLink && isShaper )
2684   {
2685     SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( me );
2686     if ( !meshSO->_is_nil() )
2687       _gen_i->SetPixMap(meshSO, "ICON_SMESH_TREE_GEOM_MODIF");
2688   }
2689 }
2690
2691 //=============================================================================
2692 /*!
2693  * \brief Update objects depending on changed geom groups
2694  *
2695  * NPAL16168: geometrical group edition from a submesh don't modify mesh computation
2696  * issue 0020210: Update of a smesh group after modification of the associated geom group
2697  */
2698 //=============================================================================
2699
2700 void SMESH_Mesh_i::CheckGeomGroupModif()
2701 {
2702   // remove sub-meshes referring a removed sub-shapes (if main shape still exists)
2703   SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
2704   GEOM::GEOM_Object_var  mainGO = GetShapeToMesh();
2705   SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( SMESH::SMESH_Mesh_var( _this() ));
2706   if ( !mainGO->_is_nil() && !meshSO->_is_nil() )
2707   {
2708     SALOMEDS::SObject_wrap rootSO, geomRefSO, geomSO;
2709     for ( CORBA::Long tag = SMESH::Tag_FirstSubMesh; tag <= SMESH::Tag_LastSubMesh; ++tag )
2710       if ( meshSO->FindSubObject( tag, rootSO.inout() ))
2711       {
2712         int nbValid = 0, nbRemoved = 0;
2713         SALOMEDS::ChildIterator_wrap chItr = _gen_i->getStudyServant()->NewChildIterator( rootSO );
2714         for ( ; chItr->More(); chItr->Next() )
2715         {
2716           SALOMEDS::SObject_wrap smSO = chItr->Value(); // sub-mesh SO
2717           if ( !smSO->_is_nil() &&
2718                smSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
2719                geomRefSO->ReferencedObject( geomSO.inout() )) // find geometry by reference
2720           {
2721             CORBA::Object_var  geomObj = _gen_i->SObjectToObject( geomSO );
2722             GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( geomObj );
2723             if ( !geom->_non_existent() )
2724             {
2725               ++nbValid;
2726               continue; // keep the sub-mesh
2727             }
2728           }
2729           CORBA::Object_var     smObj = _gen_i->SObjectToObject( smSO );
2730           SMESH::SMESH_subMesh_var sm = SMESH::SMESH_subMesh::_narrow( smObj );
2731           if ( !sm->_is_nil() && !sm->_non_existent() )
2732           {
2733             GEOM::GEOM_Object_var smGeom = sm->GetSubShape();
2734             if ( smGeom->_is_nil() )
2735             {
2736               RemoveSubMesh( sm );
2737               ++nbRemoved;
2738             }
2739           }
2740           else
2741           {
2742             if ( _preMeshInfo )
2743               _preMeshInfo->ForgetAllData(); // unknown hypothesis modified
2744             builder->RemoveObjectWithChildren( smSO ); // sub-shape removed before loading SMESH
2745             ++nbRemoved;
2746           }
2747         }
2748         if ( /*nbRemoved > 0 &&*/ nbValid == 0 )
2749           builder->RemoveObjectWithChildren( rootSO );
2750       }
2751   }
2752
2753   // check for removed sub-shapes and convert geom dependent groups into standalone ones
2754   std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
2755   while ( i_gr != _mapGroups.end())
2756   {
2757     SMESH::SMESH_GroupBase_ptr group = i_gr->second;
2758     ++i_gr;
2759     SALOMEDS::SObject_wrap        groupSO = _gen_i->ObjectToSObject( group ), refSO, geomSO;
2760     SMESH::SMESH_GroupOnGeom_var   onGeom = SMESH::SMESH_GroupOnGeom::_narrow  ( group );
2761     SMESH::SMESH_GroupOnFilter_var onFilt = SMESH::SMESH_GroupOnFilter::_narrow( group );
2762     bool isValidGeom = false;
2763     if ( !onGeom->_is_nil() )
2764     {
2765       isValidGeom = ( ! GEOM::GEOM_Object_var( onGeom->GetShape() )->_is_nil() ); // check TopoDS
2766       if ( !isValidGeom ) // check reference
2767       {
2768         isValidGeom = ( ! groupSO->_is_nil() &&
2769                         groupSO->FindSubObject( SMESH::Tag_RefOnShape, refSO.inout() ) &&
2770                         refSO->ReferencedObject( geomSO.inout() ) &&
2771                         ! geomSO->_is_nil() &&
2772                         !CORBA::is_nil( CORBA::Object_var( geomSO->GetObject() )));
2773       }
2774     }
2775     else if ( !onFilt->_is_nil() )
2776     {
2777       isValidGeom = isValidGeomFilter( onFilt->GetFilter() );
2778     }
2779     else // standalone
2780     {
2781       isValidGeom = ( !groupSO->_is_nil() &&
2782                       !groupSO->FindSubObject( SMESH::Tag_RefOnShape, refSO.inout() ));
2783     }
2784     if ( !isValidGeom )
2785     {
2786       if ( !IsLoaded() || group->IsEmpty() )
2787       {
2788         RemoveGroup( group );
2789       }
2790       else if ( !onGeom->_is_nil() || !onFilt->_is_nil() )
2791       {
2792         SMESH::SMESH_Group_var ( ConvertToStandalone( group ));
2793       }
2794       else // is it possible?
2795       {
2796         builder->RemoveObjectWithChildren( refSO );
2797       }
2798     }
2799   }
2800
2801
2802   if ( !_impl->HasShapeToMesh() ) return;
2803
2804   SMESH::smIdType nbEntities = NbNodes() + NbElements();
2805
2806   // Check if group contents changed
2807
2808   typedef map< string, TopoDS_Shape > TEntry2Geom;
2809   TEntry2Geom newGroupContents;
2810
2811   list<TGeomGroupData>::iterator
2812     data = _geomGroupData.begin(), dataEnd = _geomGroupData.end();
2813   for ( ; data != dataEnd; ++data )
2814   {
2815     pair< TEntry2Geom::iterator, bool > it_new =
2816       newGroupContents.insert( make_pair( data->_groupEntry, TopoDS_Shape() ));
2817     bool processedGroup    = !it_new.second;
2818     TopoDS_Shape& newShape = it_new.first->second;
2819     if ( !processedGroup )
2820       newShape = newGroupShape( *data, ONLY_IF_CHANGED );
2821     if ( newShape.IsNull() )
2822       continue; // no changes
2823
2824     if ( _preMeshInfo )
2825       _preMeshInfo->ForgetOrLoad();
2826
2827     if ( processedGroup ) { // update group indices
2828       list<TGeomGroupData>::iterator data2 = data;
2829       for ( --data2; data2->_groupEntry != data->_groupEntry; --data2) {}
2830       data->_indices = data2->_indices;
2831     }
2832
2833     // Update SMESH objects according to new GEOM group contents
2834
2835     SMESH::SMESH_subMesh_var submesh = SMESH::SMESH_subMesh::_narrow( data->_smeshObject );
2836     if ( !submesh->_is_nil() ) // -------------- Sub mesh ---------------------
2837     {
2838       int oldID = submesh->GetId();
2839       if ( !_mapSubMeshIor.count( oldID ))
2840         continue;
2841       TopoDS_Shape oldShape = _mapSubMesh[oldID]->GetSubShape();
2842
2843       // update hypotheses
2844       list <const SMESHDS_Hypothesis * > hyps = _impl->GetHypothesisList(oldShape);
2845       list <const SMESHDS_Hypothesis * >::iterator hypIt;
2846       for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2847       {
2848         _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
2849         _impl->AddHypothesis   ( newShape, (*hypIt)->GetID());
2850       }
2851       // care of submeshes
2852       SMESH_subMesh* newSubmesh = _impl->GetSubMesh( newShape );
2853       int newID = newSubmesh->GetId();
2854       if ( newID != oldID ) {
2855         _mapSubMesh   [ newID ] = newSubmesh;
2856         _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2857         _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2858         _mapSubMesh.   erase(oldID);
2859         _mapSubMesh_i. erase(oldID);
2860         _mapSubMeshIor.erase(oldID);
2861         _mapSubMesh_i [ newID ]->changeLocalId( newID );
2862       }
2863       continue;
2864     }
2865
2866     SMESH::SMESH_GroupOnGeom_var smeshGroup =
2867       SMESH::SMESH_GroupOnGeom::_narrow( data->_smeshObject );
2868     if ( !smeshGroup->_is_nil() ) // ------------ GROUP -----------------------
2869     {
2870       SMESH_GroupOnGeom_i* group_i = SMESH::DownCast<SMESH_GroupOnGeom_i*>( smeshGroup );
2871       if ( group_i ) {
2872         ::SMESH_Group* group = _impl->GetGroup( group_i->GetLocalID() );
2873         SMESHDS_GroupOnGeom* ds = static_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() );
2874         ds->SetShape( newShape );
2875       }
2876       continue;
2877     }
2878
2879     SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( data->_smeshObject );
2880     if ( !mesh->_is_nil() ) // -------------- MESH ----------------------------
2881     {
2882       // Remove groups and submeshes basing on removed sub-shapes
2883
2884       TopTools_MapOfShape newShapeMap;
2885       TopoDS_Iterator shapeIt( newShape );
2886       for ( ; shapeIt.More(); shapeIt.Next() )
2887         newShapeMap.Add( shapeIt.Value() );
2888
2889       SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
2890       for ( shapeIt.Initialize( meshDS->ShapeToMesh() ); shapeIt.More(); shapeIt.Next() )
2891       {
2892         if ( newShapeMap.Contains( shapeIt.Value() ))
2893           continue;
2894         TopTools_IndexedMapOfShape oldShapeMap;
2895         TopExp::MapShapes( shapeIt.Value(), oldShapeMap );
2896         for ( int i = 1; i <= oldShapeMap.Extent(); ++i )
2897         {
2898           const TopoDS_Shape& oldShape = oldShapeMap(i);
2899           int oldInd = meshDS->ShapeToIndex( oldShape );
2900           // -- submeshes --
2901           map<int, SMESH::SMESH_subMesh_ptr>::iterator i_smIor = _mapSubMeshIor.find( oldInd );
2902           if ( i_smIor != _mapSubMeshIor.end() ) {
2903             RemoveSubMesh( i_smIor->second ); // one submesh per shape index
2904           }
2905           // --- groups ---
2906           map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.begin();
2907           for ( ; i_grp != _mapGroups.end(); ++i_grp )
2908           {
2909             // check if a group bases on oldInd shape
2910             SMESHDS_GroupOnGeom* grpOnGeom = 0;
2911             if ( ::SMESH_Group* g = _impl->GetGroup( i_grp->first ))
2912               grpOnGeom = dynamic_cast<SMESHDS_GroupOnGeom*>( g->GetGroupDS() );
2913             if ( grpOnGeom && oldShape.IsSame( grpOnGeom->GetShape() ))
2914             { // remove
2915               RemoveGroup( i_grp->second ); // several groups can base on same shape
2916               i_grp = _mapGroups.begin(); // _mapGroups changed - restart iteration
2917             }
2918           }
2919         }
2920       }
2921       // Reassign hypotheses and update groups after setting the new shape to mesh
2922
2923       // collect anassigned hypotheses
2924       typedef list< pair< TIndexedShape, list<const SMESHDS_Hypothesis*> > > TShapeHypList;
2925       list <const SMESHDS_Hypothesis * >::const_iterator hypIt;
2926       TShapeHypList assignedHyps;
2927       for ( int i = 1; i <= meshDS->MaxShapeIndex(); ++i )
2928       {
2929         const TopoDS_Shape& oldShape = meshDS->IndexToShape(i);
2930         list<const SMESHDS_Hypothesis*> hyps = meshDS->GetHypothesis( oldShape );// copy
2931         if ( !hyps.empty() ) {
2932           assignedHyps.push_back( make_pair( TIndexedShape(i,oldShape), hyps ));
2933           for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2934             _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
2935         }
2936       }
2937       // collect shapes supporting groups
2938       typedef list < pair< TIndexedShape, SMDSAbs_ElementType > > TShapeTypeList;
2939       TShapeTypeList groupData;
2940       const set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
2941       set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2942       for ( ; grIt != groups.end(); ++grIt )
2943       {
2944         if ( SMESHDS_GroupOnGeom* gog = dynamic_cast<SMESHDS_GroupOnGeom*>( *grIt ))
2945           groupData.push_back
2946             ( make_pair( TIndexedShape( gog->GetID(),gog->GetShape()), gog->GetType()));
2947       }
2948       // set new shape to mesh -> DS of sub-meshes and geom groups is deleted
2949       _impl->Clear();
2950       _impl->ShapeToMesh( TopoDS_Shape() ); // IPAL52730
2951       _impl->ShapeToMesh( newShape );
2952
2953       // reassign hypotheses
2954       TShapeHypList::iterator indS_hyps = assignedHyps.begin();
2955       for ( ; indS_hyps != assignedHyps.end(); ++indS_hyps )
2956       {
2957         TIndexedShape&                   geom = indS_hyps->first;
2958         list<const SMESHDS_Hypothesis*>& hyps = indS_hyps->second;
2959         int oldID = geom._index;
2960         int newID = meshDS->ShapeToIndex( geom._shape );
2961         if ( oldID == 1 ) { // main shape
2962           newID = 1;
2963           geom._shape = newShape;
2964         }
2965         if ( !newID )
2966           continue;
2967         for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2968           _impl->AddHypothesis( geom._shape, (*hypIt)->GetID());
2969         // care of sub-meshes
2970         SMESH_subMesh* newSubmesh = _impl->GetSubMesh( geom._shape );
2971         if ( newID != oldID ) {
2972           _mapSubMesh   [ newID ] = newSubmesh;
2973           _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2974           _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2975           _mapSubMesh.   erase(oldID);
2976           _mapSubMesh_i. erase(oldID);
2977           _mapSubMeshIor.erase(oldID);
2978           _mapSubMesh_i [ newID ]->changeLocalId( newID );
2979         }
2980       }
2981       // recreate groups
2982       TShapeTypeList::iterator geomType = groupData.begin();
2983       for ( ; geomType != groupData.end(); ++geomType )
2984       {
2985         const TIndexedShape& geom = geomType->first;
2986         int oldID = geom._index;
2987         if ( _mapGroups.find( oldID ) == _mapGroups.end() )
2988           continue;
2989         // get group name
2990         SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( _mapGroups[oldID] );
2991         CORBA::String_var      name    = groupSO->GetName();
2992         // update
2993         if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>(_mapGroups[oldID]))
2994           if ( SMESH_Group* group = _impl->AddGroup( geomType->second, name.in(),
2995                                                      /*id=*/-1, geom._shape ))
2996             group_i->changeLocalId( group->GetID() );
2997       }
2998
2999       break; // everything has been updated
3000
3001     } // update mesh
3002   } // loop on group data
3003
3004   // Update icons
3005
3006   SMESH::smIdType newNbEntities = NbNodes() + NbElements();
3007   list< SALOMEDS::SObject_wrap > soToUpdateIcons;
3008   if ( newNbEntities != nbEntities )
3009   {
3010     // Add all SObjects with icons to soToUpdateIcons
3011     soToUpdateIcons.push_back( _gen_i->ObjectToSObject( _this() )); // mesh
3012
3013     for (map<int, SMESH::SMESH_subMesh_ptr>::iterator i_sm = _mapSubMeshIor.begin();
3014          i_sm != _mapSubMeshIor.end(); ++i_sm ) // submeshes
3015       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( i_sm->second ));
3016
3017     for ( map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
3018           i_gr != _mapGroups.end(); ++i_gr ) // groups
3019       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( i_gr->second ));
3020   }
3021
3022   list< SALOMEDS::SObject_wrap >::iterator so = soToUpdateIcons.begin();
3023   for ( ; so != soToUpdateIcons.end(); ++so )
3024     _gen_i->SetPixMap( *so, "ICON_SMESH_TREE_MESH_WARN" );
3025 }
3026
3027 //=============================================================================
3028 /*!
3029  * \brief Create standalone group from a group on geometry or filter
3030  */
3031 //=============================================================================
3032
3033 SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupBase_ptr theGroup )
3034 {
3035   SMESH::SMESH_Group_var aGroup;
3036
3037   SMESH_TRY;
3038
3039   if ( _preMeshInfo )
3040     _preMeshInfo->FullLoadFromFile();
3041
3042   if ( theGroup->_is_nil() )
3043     return aGroup._retn();
3044
3045   SMESH_GroupBase_i* aGroupToRem = SMESH::DownCast<SMESH_GroupBase_i*>( theGroup );
3046   if ( !aGroupToRem )
3047     return aGroup._retn();
3048
3049   const bool isOnFilter = ( SMESH::DownCast< SMESH_GroupOnFilter_i* > ( theGroup ));
3050
3051   const int anId = aGroupToRem->GetLocalID();
3052   if ( !_impl->ConvertToStandalone( anId ) )
3053     return aGroup._retn();
3054   removeGeomGroupData( theGroup );
3055
3056   SMESH_GroupBase_i* aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
3057
3058   // remove old instance of group from own map
3059   { SMESH::SMESH_GroupBase_var var( _mapGroups[anId] ); } // decref CORBA object
3060   _mapGroups.erase( anId );
3061
3062   SALOMEDS::StudyBuilder_var builder;
3063   SALOMEDS::SObject_wrap     aGroupSO;
3064   SALOMEDS::Study_var        aStudy = SMESH_Gen_i::GetSMESHGen()->getStudyServant();
3065   if ( !aStudy->_is_nil() ) {
3066     builder  = aStudy->NewBuilder();
3067     aGroupSO = _gen_i->ObjectToSObject( theGroup );
3068     if ( !aGroupSO->_is_nil() )
3069     {
3070       // remove reference to geometry
3071       SALOMEDS::ChildIterator_wrap chItr = aStudy->NewChildIterator(aGroupSO);
3072       for ( ; chItr->More(); chItr->Next() )
3073       {
3074         // Remove group's child SObject
3075         SALOMEDS::SObject_wrap so = chItr->Value();
3076         builder->RemoveObject( so );
3077       }
3078       // Update Python script
3079       TPythonDump() << aGroupSO << " = " << SMESH::SMESH_Mesh_var(_this())
3080                     << ".ConvertToStandalone( " << aGroupSO << " )";
3081
3082       // change icon of Group on Filter
3083       if ( isOnFilter )
3084       {
3085         // SMESH::array_of_ElementType_var elemTypes = aGroupImpl->GetTypes();
3086         // const int isEmpty = ( elemTypes->length() == 0 );
3087         // if ( !isEmpty )
3088         {
3089           SALOMEDS::GenericAttribute_wrap anAttr =
3090             builder->FindOrCreateAttribute( aGroupSO, "AttributePixMap" );
3091           SALOMEDS::AttributePixMap_wrap pm = anAttr;
3092           pm->SetPixMap( "ICON_SMESH_TREE_GROUP" );
3093         }
3094       }
3095     }
3096   }
3097
3098   // remember new group in own map
3099   aGroup = SMESH::SMESH_Group::_narrow( aGroupImpl->_this() );
3100   _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
3101
3102   // register CORBA object for persistence
3103   _gen_i->RegisterObject( aGroup );
3104
3105   CORBA::String_var ior = _gen_i->GetORB()->object_to_string( aGroup );
3106   builder->SetIOR( aGroupSO, ior.in() ); //  == aGroup->Register();
3107   //aGroup->Register();
3108   aGroupToRem->UnRegister();
3109
3110   SMESH_CATCH( SMESH::throwCorbaException );
3111
3112   return aGroup._retn();
3113 }
3114
3115 //================================================================================
3116 /*!
3117  * \brief Create a sub-mesh on a given sub-shape
3118  */
3119 //================================================================================
3120
3121 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::createSubMesh( GEOM::GEOM_Object_ptr theSubShapeObject )
3122 {
3123   if(MYDEBUG) MESSAGE( "createSubMesh" );
3124   TopoDS_Shape  myLocSubShape = _gen_i->GeomObjectToShape(theSubShapeObject);
3125   ::SMESH_subMesh * mySubMesh = _impl->GetSubMesh(myLocSubShape);
3126   int               subMeshId = 0;
3127
3128   SMESH_subMesh_i * subMeshServant;
3129   if ( mySubMesh )
3130   {
3131     subMeshId = mySubMesh->GetId();
3132     subMeshServant = new SMESH_subMesh_i(myPOA, _gen_i, this, subMeshId);
3133   }
3134   else // "invalid sub-mesh"
3135   {
3136     // The invalid sub-mesh is created for the case where a valid sub-shape not found
3137     // by SMESH_Gen_i::CopyMeshWithGeom(). The invalid sub-mesh has GetId() < 0.
3138     if ( _mapSubMesh.empty() )
3139       subMeshId = -1;
3140     else
3141       subMeshId = _mapSubMesh.begin()->first - 1;
3142     subMeshServant = new SMESH_Invalid_subMesh_i(myPOA, _gen_i, this, subMeshId, theSubShapeObject);
3143   }
3144
3145   SMESH::SMESH_subMesh_var subMesh = subMeshServant->_this();
3146
3147   _mapSubMesh   [subMeshId] = mySubMesh;
3148   _mapSubMesh_i [subMeshId] = subMeshServant;
3149   _mapSubMeshIor[subMeshId] = SMESH::SMESH_subMesh::_duplicate( subMesh );
3150
3151   subMeshServant->Register();
3152
3153   // register CORBA object for persistence
3154   int nextId = _gen_i->RegisterObject( subMesh );
3155   if(MYDEBUG) { MESSAGE( "Add submesh to map with id = "<< nextId); }
3156   else        { (void)nextId; } // avoid "unused variable" warning
3157
3158   // to track changes of GEOM groups
3159   if ( subMeshId > 0 )
3160     addGeomGroupData( theSubShapeObject, subMesh );
3161
3162   return subMesh._retn();
3163 }
3164
3165 //================================================================================
3166 /*!
3167  * \brief Return an existing sub-mesh based on a sub-shape with the given ID
3168  */
3169 //================================================================================
3170
3171 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::getSubMesh(int shapeID)
3172 {
3173   map<int, SMESH::SMESH_subMesh_ptr>::iterator it = _mapSubMeshIor.find( shapeID );
3174   if ( it == _mapSubMeshIor.end() )
3175     return SMESH::SMESH_subMesh::_nil();
3176
3177   return SMESH::SMESH_subMesh::_duplicate( (*it).second );
3178 }
3179
3180 //================================================================================
3181 /*!
3182  * \brief Remove a sub-mesh based on the given sub-shape
3183  */
3184 //================================================================================
3185
3186 bool SMESH_Mesh_i::removeSubMesh (SMESH::SMESH_subMesh_ptr theSubMesh,
3187                                   GEOM::GEOM_Object_ptr    theSubShapeObject )
3188 {
3189   bool isHypChanged = false;
3190   if ( theSubMesh->_is_nil() /*|| theSubShapeObject->_is_nil()*/ )
3191     return isHypChanged;
3192
3193   const int subMeshId = theSubMesh->GetId();
3194
3195   if ( theSubShapeObject->_is_nil() )  // not published shape (IPAL13617)
3196   {
3197     SMESH_subMesh* sm;
3198     if (( _mapSubMesh.count( subMeshId )) &&
3199         ( sm = _impl->GetSubMeshContaining( subMeshId )))
3200     {
3201       TopoDS_Shape S = sm->GetSubShape();
3202       if ( !S.IsNull() )
3203       {
3204         list<const SMESHDS_Hypothesis*> hyps = _impl->GetHypothesisList( S );
3205         isHypChanged = !hyps.empty();
3206         if ( isHypChanged && _preMeshInfo )
3207           _preMeshInfo->ForgetOrLoad();
3208         list<const SMESHDS_Hypothesis*>::const_iterator hyp = hyps.begin();
3209         for ( ; hyp != hyps.end(); ++hyp )
3210           _impl->RemoveHypothesis(S, (*hyp)->GetID());
3211       }
3212     }
3213   }
3214   else
3215   {
3216     try {
3217       SMESH::ListOfHypothesis_var aHypList = GetHypothesisList( theSubShapeObject );
3218       isHypChanged = ( aHypList->length() > 0 );
3219       for ( int i = 0, n = aHypList->length(); i < n; i++ ) {
3220         removeHypothesis( theSubShapeObject, aHypList[i] );
3221       }
3222     }
3223     catch( const SALOME::SALOME_Exception& ) {
3224       INFOS("SMESH_Mesh_i::removeSubMesh(): exception caught!");
3225     }
3226     removeGeomGroupData( theSubShapeObject );
3227   }
3228
3229   // remove a servant
3230   std::map<int, SMESH_subMesh_i*>::iterator id_smi = _mapSubMesh_i.find( subMeshId );
3231   if ( id_smi != _mapSubMesh_i.end() )
3232     id_smi->second->UnRegister();
3233
3234   // remove a CORBA object
3235   std::map<int, SMESH::SMESH_subMesh_ptr>::iterator id_smptr = _mapSubMeshIor.find( subMeshId );
3236   if ( id_smptr != _mapSubMeshIor.end() )
3237     SMESH::SMESH_subMesh_var( id_smptr->second );
3238
3239   _mapSubMesh.erase(subMeshId);
3240   _mapSubMesh_i.erase(subMeshId);
3241   _mapSubMeshIor.erase(subMeshId);
3242
3243   return isHypChanged;
3244 }
3245
3246 //================================================================================
3247 /*!
3248  * \brief Create a group. Group type depends on given arguments
3249  */
3250 //================================================================================
3251
3252 SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType        theElemType,
3253                                                       const char*               theName,
3254                                                       const int                 theID,
3255                                                       const TopoDS_Shape&       theShape,
3256                                                       const SMESH_PredicatePtr& thePredicate )
3257 {
3258   std::string newName;
3259   if ( !theName || !theName[0] )
3260   {
3261     std::set< std::string > presentNames;
3262     std::map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator i_gr = _mapGroups.begin();
3263     for ( ; i_gr != _mapGroups.end(); ++i_gr )
3264     {
3265       CORBA::String_var name = i_gr->second->GetName();
3266       presentNames.insert( name.in() );
3267     }
3268     do {
3269       newName = "noname_Group_" + SMESH_Comment( presentNames.size() + 1 );
3270     } while ( !presentNames.insert( newName ).second );
3271     theName = newName.c_str();
3272   }
3273   SMESH::SMESH_GroupBase_var aGroup;
3274   if ( SMESH_Group* g = _impl->AddGroup( (SMDSAbs_ElementType)theElemType, theName,
3275                                          theID, theShape, thePredicate ))
3276   {
3277     int anId = g->GetID();
3278     SMESH_GroupBase_i* aGroupImpl;
3279     if ( !theShape.IsNull() )
3280       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
3281     else if ( thePredicate )
3282       aGroupImpl = new SMESH_GroupOnFilter_i( SMESH_Gen_i::GetPOA(), this, anId );
3283     else
3284       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
3285
3286     aGroup = aGroupImpl->_this();
3287     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
3288     aGroupImpl->Register();
3289
3290     // register CORBA object for persistence
3291     int nextId = _gen_i->RegisterObject( aGroup );
3292     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
3293     else        { nextId = ( nextId > 0 ); } // avoid "unused variable" warning in release mode
3294
3295     // to track changes of GEOM groups
3296     if ( !theShape.IsNull() ) {
3297       GEOM::GEOM_Object_var geom = _gen_i->ShapeToGeomObject( theShape );
3298       addGeomGroupData( geom, aGroup );
3299     }
3300   }
3301   return aGroup._retn();
3302 }
3303
3304 //=============================================================================
3305 /*!
3306  * SMESH_Mesh_i::removeGroup
3307  *
3308  * Should be called by ~SMESH_Group_i()
3309  */
3310 //=============================================================================
3311
3312 void SMESH_Mesh_i::removeGroup( const int theId )
3313 {
3314   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::removeGroup()" );
3315   if ( _mapGroups.find( theId ) != _mapGroups.end() ) {
3316     SMESH::SMESH_GroupBase_var group = _mapGroups[theId];
3317     _mapGroups.erase( theId );
3318     removeGeomGroupData( group );
3319     if ( !_impl->RemoveGroup( theId ))
3320     {
3321       // it seems to be a call up from _impl caused by hyp modification (issue 0020918)
3322       RemoveGroup( group );
3323     }
3324     group->UnRegister();
3325   }
3326 }
3327
3328 //================================================================================
3329 /*!
3330  * \brief Return a log that can be used to move another mesh to the same state as this one
3331  */
3332 //================================================================================
3333
3334 SMESH::log_array * SMESH_Mesh_i::GetLog(CORBA::Boolean clearAfterGet)
3335 {
3336   SMESH::log_array_var aLog;
3337
3338   SMESH_TRY;
3339   if ( _preMeshInfo )
3340     _preMeshInfo->FullLoadFromFile();
3341
3342   list < SMESHDS_Command * >logDS = _impl->GetLog();
3343   aLog = new SMESH::log_array;
3344   int indexLog = 0;
3345   int lg = logDS.size();
3346   aLog->length(lg);
3347   list < SMESHDS_Command * >::iterator its = logDS.begin();
3348   while(its != logDS.end()){
3349     SMESHDS_Command *com = *its;
3350     int comType = com->GetType();
3351     smIdType lgcom = com->GetNumber();
3352     const list < smIdType >&intList = com->GetIndexes();
3353     int inum = intList.size();
3354     list < smIdType >::const_iterator ii = intList.begin();
3355     const list < double >&coordList = com->GetCoords();
3356     int rnum = coordList.size();
3357     list < double >::const_iterator ir = coordList.begin();
3358     aLog[indexLog].commandType = comType;
3359     aLog[indexLog].number = lgcom;
3360     aLog[indexLog].coords.length(rnum);
3361     aLog[indexLog].indexes.length(inum);
3362     for(int i = 0; i < rnum; i++){
3363       aLog[indexLog].coords[i] = *ir;
3364       ir++;
3365     }
3366     for(int i = 0; i < inum; i++){
3367       aLog[indexLog].indexes[i] = *ii;
3368       ii++;
3369     }
3370     indexLog++;
3371     its++;
3372   }
3373   if(clearAfterGet)
3374     _impl->ClearLog();
3375
3376   SMESH_CATCH( SMESH::throwCorbaException );
3377
3378   return aLog._retn();
3379 }
3380
3381 //================================================================================
3382 /*!
3383  * \brief Remove the log of commands
3384  */
3385 //================================================================================
3386
3387 void SMESH_Mesh_i::ClearLog()
3388 {
3389   SMESH_TRY;
3390   _impl->ClearLog();
3391   SMESH_CATCH( SMESH::throwCorbaException );
3392 }
3393
3394 //================================================================================
3395 /*!
3396  * \brief Return a mesh ID
3397  */
3398 //================================================================================
3399
3400 CORBA::Long SMESH_Mesh_i::GetId()
3401 {
3402   return _id;
3403 }
3404
3405 //=============================================================================
3406 namespace
3407 {
3408   //!< implementation of struct used to call methods of SMESH_Mesh_i from SMESH_Mesh
3409   // issue 0020918: groups removal is caused by hyp modification
3410   // issue 0021208: to forget not loaded mesh data at hyp modification
3411   struct TCallUp_i : public SMESH_Mesh::TCallUp
3412   {
3413     SMESH_Mesh_i* _mesh;
3414     TCallUp_i(SMESH_Mesh_i* mesh):_mesh(mesh) {}
3415     void RemoveGroup (const int theGroupID) override { _mesh->removeGroup( theGroupID ); }
3416     void HypothesisModified( int hypID,
3417                              bool updIcons) override { _mesh->onHypothesisModified( hypID,
3418                                                                                     updIcons ); }
3419     void Load ()                            override { _mesh->Load(); }
3420     bool IsLoaded()                         override { return _mesh->IsLoaded(); }
3421     TopoDS_Shape GetShapeByEntry(const std::string& entry) override
3422     {
3423       GEOM::GEOM_Object_var go = SMESH_Gen_i::GetGeomObjectByEntry( entry );
3424       return SMESH_Gen_i::GeomObjectToShape( go );
3425     }
3426   };
3427 }
3428
3429 //================================================================================
3430 /*!
3431  * \brief callback from _impl to
3432  *     1) forget not loaded mesh data (issue 0021208)
3433  *     2) mark hypothesis as valid
3434  */
3435 //================================================================================
3436
3437 void SMESH_Mesh_i::onHypothesisModified(int theHypID, bool theUpdateIcons)
3438 {
3439   if ( _preMeshInfo )
3440     _preMeshInfo->ForgetOrLoad();
3441
3442   if ( theUpdateIcons )
3443   {
3444     SMESH::SMESH_Mesh_var mesh = _this();
3445     _gen_i->UpdateIcons( mesh );
3446   }
3447
3448   if ( _nbInvalidHypos != 0 )
3449   {
3450     // mark a hypothesis as valid after edition
3451     int nbInvalid = 0;
3452     SALOMEDS::SComponent_wrap smeshComp = _gen_i->PublishComponent();
3453     SALOMEDS::SObject_wrap hypRoot;
3454     if ( !smeshComp->_is_nil() &&
3455          smeshComp->FindSubObject( _gen_i->GetHypothesisRootTag(), hypRoot.inout() ))
3456     {
3457       SALOMEDS::ChildIterator_wrap anIter = _gen_i->getStudyServant()->NewChildIterator( hypRoot );
3458       for ( ; anIter->More(); anIter->Next() )
3459       {
3460         SALOMEDS::SObject_wrap    hypSO = anIter->Value();
3461         CORBA::Object_var           obj = _gen_i->SObjectToObject( hypSO );
3462         SMESH::SMESH_Hypothesis_var hyp = SMESH::SMESH_Hypothesis::_narrow( obj );
3463         if ( !hyp->_is_nil() && hyp->GetId() == theHypID )
3464           _gen_i->HighLightInvalid( hyp, false );
3465         else
3466           nbInvalid += _gen_i->IsInvalid( hypSO );
3467       }
3468     }
3469     _nbInvalidHypos = nbInvalid;
3470   }
3471 }
3472
3473 //================================================================================
3474 /*!
3475  * \brief Set mesh implementation
3476  */
3477 //================================================================================
3478
3479 void SMESH_Mesh_i::SetImpl(::SMESH_Mesh * impl)
3480 {
3481   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::SetImpl");
3482   _impl = impl;
3483   if ( _impl )
3484     _impl->SetCallUp( new TCallUp_i(this));
3485 }
3486
3487 //=============================================================================
3488 /*!
3489  * Return a mesh implementation
3490  */
3491 //=============================================================================
3492
3493 ::SMESH_Mesh & SMESH_Mesh_i::GetImpl()
3494 {
3495   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::GetImpl()");
3496   return *_impl;
3497 }
3498
3499 //=============================================================================
3500 /*!
3501  * Return mesh editor
3502  */
3503 //=============================================================================
3504
3505 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditor()
3506 {
3507   SMESH::SMESH_MeshEditor_var aMeshEdVar;
3508
3509   SMESH_TRY;
3510   if ( _preMeshInfo )
3511     _preMeshInfo->FullLoadFromFile();
3512
3513   // Create MeshEditor
3514   if ( !_editor )
3515     _editor = new SMESH_MeshEditor_i( this, false );
3516   aMeshEdVar = _editor->_this();
3517
3518   // Update Python script
3519   TPythonDump() << _editor << " = "
3520                 << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshEditor()";
3521
3522   SMESH_CATCH( SMESH::throwCorbaException );
3523
3524   return aMeshEdVar._retn();
3525 }
3526
3527 //=============================================================================
3528 /*!
3529  * Return mesh edition previewer
3530  */
3531 //=============================================================================
3532
3533 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditPreviewer()
3534 {
3535   SMESH::SMESH_MeshEditor_var aMeshEdVar;
3536
3537   SMESH_TRY;
3538   if ( _preMeshInfo )
3539     _preMeshInfo->FullLoadFromFile();
3540
3541   if ( !_previewEditor )
3542     _previewEditor = new SMESH_MeshEditor_i( this, true );
3543   aMeshEdVar = _previewEditor->_this();
3544
3545   SMESH_CATCH( SMESH::throwCorbaException );
3546
3547   return aMeshEdVar._retn();
3548 }
3549
3550 //================================================================================
3551 /*!
3552  * \brief Return true if the mesh has been edited since a last total re-compute
3553  *        and those modifications may prevent successful partial re-compute
3554  */
3555 //================================================================================
3556
3557 CORBA::Boolean SMESH_Mesh_i::HasModificationsToDiscard()
3558 {
3559   Unexpect aCatch(SALOME_SalomeException);
3560   return _impl->HasModificationsToDiscard();
3561 }
3562
3563 //================================================================================
3564 /*!
3565  * \brief Return a random unique color
3566  */
3567 //================================================================================
3568
3569 static SALOMEDS::Color getUniqueColor( const std::list<SALOMEDS::Color>& theReservedColors )
3570 {
3571   const int MAX_ATTEMPTS = 100;
3572   int cnt = 0;
3573   double tolerance = 0.5;
3574   SALOMEDS::Color col;
3575
3576   bool ok = false;
3577   while ( !ok ) {
3578     // generate random color
3579     double red    = (double)rand() / RAND_MAX;
3580     double green  = (double)rand() / RAND_MAX;
3581     double blue   = (double)rand() / RAND_MAX;
3582     // check existence in the list of the existing colors
3583     bool matched = false;
3584     std::list<SALOMEDS::Color>::const_iterator it;
3585     for ( it = theReservedColors.begin(); it != theReservedColors.end() && !matched; ++it ) {
3586       SALOMEDS::Color color = *it;
3587       double tol = fabs( color.R - red ) + fabs( color.G - green ) + fabs( color.B  - blue  );
3588       matched = tol < tolerance;
3589     }
3590     if ( (cnt+1) % 20 == 0 ) tolerance = tolerance/2;
3591     ok = ( ++cnt == MAX_ATTEMPTS ) || !matched;
3592     col.R = red;
3593     col.G = green;
3594     col.B = blue;
3595   }
3596   return col;
3597 }
3598
3599 //=============================================================================
3600 /*!
3601  * Set auto-color mode. If it is on, groups get unique random colors
3602  */
3603 //=============================================================================
3604
3605 void SMESH_Mesh_i::SetAutoColor(CORBA::Boolean theAutoColor)
3606 {
3607   Unexpect aCatch(SALOME_SalomeException);
3608   _impl->SetAutoColor(theAutoColor);
3609
3610   TPythonDump pyDump; // not to dump group->SetColor() from below code
3611   pyDump << SMESH::SMESH_Mesh_var(_this()) <<".SetAutoColor( "<<theAutoColor<<" )";
3612
3613   std::list<SALOMEDS::Color> aReservedColors;
3614   map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.begin();
3615   for ( ; it != _mapGroups.end(); it++ ) {
3616     if ( CORBA::is_nil( it->second )) continue;
3617     SALOMEDS::Color aColor = getUniqueColor( aReservedColors );
3618     it->second->SetColor( aColor );
3619     aReservedColors.push_back( aColor );
3620   }
3621 }
3622
3623 //=============================================================================
3624 /*!
3625  * Return true if auto-color mode is on
3626  */
3627 //=============================================================================
3628
3629 CORBA::Boolean SMESH_Mesh_i::GetAutoColor()
3630 {
3631   Unexpect aCatch(SALOME_SalomeException);
3632   return _impl->GetAutoColor();
3633 }
3634
3635 //=============================================================================
3636 /*!
3637  *  Check if there are groups with equal names
3638  */
3639 //=============================================================================
3640
3641 CORBA::Boolean SMESH_Mesh_i::HasDuplicatedGroupNamesMED()
3642 {
3643   return _impl->HasDuplicatedGroupNamesMED();
3644 }
3645
3646 //================================================================================
3647 /*!
3648  * \brief Care of a file before exporting mesh into it
3649  */
3650 //================================================================================
3651
3652 void SMESH_Mesh_i::PrepareForWriting (const char* file, bool overwrite)
3653 {
3654   SMESH_File aFile( file, false );
3655   SMESH_Comment msg;
3656   if ( aFile.exists() ) {
3657     // existing filesystem node
3658     if ( !aFile.isDirectory() ) {
3659       if ( aFile.openForWriting() ) {
3660         if ( overwrite && ! aFile.remove()) {
3661           msg << "Can't replace " << aFile.getName();
3662         }
3663       } else {
3664         msg << "Can't write into " << aFile.getName();
3665       }
3666     } else {
3667       msg << "Location " << aFile.getName() << " is not a file";
3668     }
3669   }
3670   else {
3671     // nonexisting file; check if it can be created
3672     if ( !aFile.openForWriting() ) {
3673       msg << "You cannot create the file "
3674           << aFile.getName()
3675           << ". Check the directory existence and access rights";
3676     }
3677     aFile.remove();
3678   }
3679
3680   if ( !msg.empty() )
3681   {
3682     msg << ".";
3683     THROW_SALOME_CORBA_EXCEPTION(msg.c_str(), SALOME::BAD_PARAM);
3684   }
3685 }
3686
3687 /*!
3688   Return a MeshName
3689  */
3690 std::string SMESH_Mesh_i::generateMeshName()
3691 {
3692   string aMeshName = "Mesh";
3693   SALOMEDS::Study_var aStudy = SMESH_Gen_i::GetSMESHGen()->getStudyServant();
3694   if ( !aStudy->_is_nil() )
3695   {
3696     SALOMEDS::SObject_wrap aMeshSO = _gen_i->ObjectToSObject(  _this() );
3697     if ( !aMeshSO->_is_nil() )
3698     {
3699       CORBA::String_var name = aMeshSO->GetName();
3700       aMeshName = name;
3701     }
3702   }
3703   return aMeshName;
3704 }
3705
3706 //================================================================================
3707 /*!
3708  * \brief Prepare a file for export and pass names of mesh groups from study to mesh DS
3709  *  \param file - file name
3710  *  \param overwrite - to erase the file or not
3711  *  \retval string - mesh name
3712  */
3713 //================================================================================
3714
3715 string SMESH_Mesh_i::prepareMeshNameAndGroups(const char*    file,
3716                                               CORBA::Boolean overwrite)
3717 {
3718   // Perform Export
3719   PrepareForWriting(file, overwrite);
3720   string aMeshName(this->generateMeshName());
3721   SALOMEDS::Study_var aStudy = SMESH_Gen_i::GetSMESHGen()->getStudyServant();
3722   if ( !aStudy->_is_nil() ) {
3723     SALOMEDS::SObject_wrap aMeshSO = _gen_i->ObjectToSObject(  _this() );
3724     if ( !aMeshSO->_is_nil() ) {
3725       // asv : 27.10.04 : fix of 6903: check for StudyLocked before adding attributes
3726       if ( !aStudy->GetProperties()->IsLocked() )
3727       {
3728         SALOMEDS::GenericAttribute_wrap anAttr;
3729         SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder();
3730         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeExternalFileDef");
3731         SALOMEDS::AttributeExternalFileDef_wrap aFileName = anAttr;
3732         ASSERT(!aFileName->_is_nil());
3733         aFileName->SetValue(file);
3734         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeFileType");
3735         SALOMEDS::AttributeFileType_wrap aFileType = anAttr;
3736         ASSERT(!aFileType->_is_nil());
3737         aFileType->SetValue("FICHIERMED");
3738       }
3739     }
3740   }
3741   // Update Python script
3742   // set name of mesh before export
3743   TPythonDump() << _gen_i << ".SetName("
3744                 << SMESH::SMESH_Mesh_var(_this()) << ", '" << aMeshName.c_str() << "')";
3745
3746   // check names of groups
3747   checkGroupNames();
3748
3749   return aMeshName;
3750 }
3751
3752 //================================================================================
3753 /*!
3754  * \brief Export to MED file
3755  */
3756 //================================================================================
3757
3758 void SMESH_Mesh_i::ExportMED(const char*    file,
3759                              CORBA::Boolean auto_groups,
3760                              CORBA::Long    version,
3761                              CORBA::Boolean overwrite,
3762                              CORBA::Boolean autoDimension)
3763 {
3764   //MESSAGE("MED minor version: "<< minor);
3765   SMESH_TRY;
3766   if ( _preMeshInfo )
3767     _preMeshInfo->FullLoadFromFile();
3768
3769   string aMeshName = prepareMeshNameAndGroups(file, overwrite);
3770   _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version, 0, autoDimension );
3771
3772   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportMED( r'"
3773                 << file << "', "
3774                 << "auto_groups=" <<auto_groups << ", "
3775                 << "version=" << version <<  ", "
3776                 << "overwrite=" << overwrite << ", "
3777                 << "meshPart=None, "
3778                 << "autoDimension=" << autoDimension << " )";
3779
3780   SMESH_CATCH( SMESH::throwCorbaException );
3781 }
3782
3783 CORBA::LongLong SMESH_Mesh_i::ExportMEDCoupling(CORBA::Boolean auto_groups, CORBA::Boolean autoDimension)
3784 {
3785   MEDCoupling::MCAuto<MEDCoupling::DataArrayByte> data;
3786   SMESH_TRY;
3787   // TODO : Fix me ! 2 next lines are required
3788   if( !this->_gen_i->isSSLMode() )
3789     SMESH::throwCorbaException("SMESH_Mesh_i::ExportMEDCoupling : only for embedded mode !");
3790   if ( _preMeshInfo )
3791     _preMeshInfo->FullLoadFromFile();
3792
3793   string aMeshName = this->generateMeshName();
3794   data = _impl->ExportMEDCoupling( aMeshName.c_str(), auto_groups, 0, autoDimension );
3795   SMESH_CATCH( SMESH::throwCorbaException );
3796   MEDCoupling::DataArrayByte *ret(data.retn());
3797   return reinterpret_cast<CORBA::LongLong>(ret);
3798 }
3799
3800 //================================================================================
3801 /*!
3802  * \brief Export a mesh to a SAUV file
3803  */
3804 //================================================================================
3805
3806 void SMESH_Mesh_i::ExportSAUV( const char* file, CORBA::Boolean auto_groups )
3807 {
3808   SMESH_TRY;
3809   if ( _preMeshInfo )
3810     _preMeshInfo->FullLoadFromFile();
3811
3812   string aMeshName = prepareMeshNameAndGroups(file, true);
3813   TPythonDump() << SMESH::SMESH_Mesh_var( _this())
3814                 << ".ExportSAUV( r'" << file << "', " << auto_groups << " )";
3815   _impl->ExportSAUV(file, aMeshName.c_str(), auto_groups);
3816
3817   SMESH_CATCH( SMESH::throwCorbaException );
3818 }
3819
3820
3821 //================================================================================
3822 /*!
3823  * \brief Export a mesh to a DAT file
3824  */
3825 //================================================================================
3826
3827 void SMESH_Mesh_i::ExportDAT (const char *file, CORBA::Boolean renumber )
3828 {
3829   SMESH_TRY;
3830   if ( _preMeshInfo )
3831     _preMeshInfo->FullLoadFromFile();
3832
3833   // check names of groups
3834   checkGroupNames();
3835   // Update Python script
3836   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
3837                 << ".ExportDAT( r'" << file<< ", " << renumber << "' )";
3838
3839   // Perform Export
3840   PrepareForWriting( file );
3841   _impl->ExportDAT( file, /*part=*/nullptr, renumber );
3842
3843   SMESH_CATCH( SMESH::throwCorbaException );
3844 }
3845
3846 //================================================================================
3847 /*!
3848  * \brief Export a mesh to an UNV file
3849  */
3850 //================================================================================
3851
3852 void SMESH_Mesh_i::ExportUNV (const char *file, CORBA::Boolean renumber)
3853 {
3854   SMESH_TRY;
3855   if ( _preMeshInfo )
3856     _preMeshInfo->FullLoadFromFile();
3857
3858   // check names of groups
3859   checkGroupNames();
3860   // Update Python script
3861   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
3862                 << ".ExportUNV( r'" << file << "' " << renumber << "' )";
3863
3864   // Perform Export
3865   PrepareForWriting( file );
3866   _impl->ExportUNV( file, /*part=*/nullptr, renumber );
3867
3868   SMESH_CATCH( SMESH::throwCorbaException );
3869 }
3870
3871 //================================================================================
3872 /*!
3873  * \brief Export a mesh to an STL file
3874  */
3875 //================================================================================
3876
3877 void SMESH_Mesh_i::ExportSTL (const char *file, const bool isascii)
3878 {
3879   SMESH_TRY;
3880   if ( _preMeshInfo )
3881     _preMeshInfo->FullLoadFromFile();
3882
3883   // check names of groups
3884   checkGroupNames();
3885   // Update Python script
3886   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
3887                 << ".ExportSTL( r'" << file << "', " << isascii << " )";
3888
3889   CORBA::String_var name;
3890   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( _this() );
3891   if ( !so->_is_nil() )
3892     name = so->GetName();
3893
3894   // Perform Export
3895   PrepareForWriting( file );
3896   _impl->ExportSTL( file, isascii, name.in() );
3897
3898   SMESH_CATCH( SMESH::throwCorbaException );
3899 }
3900
3901 //================================================================================
3902
3903 class MEDFileSpeCls
3904 {
3905 public:
3906   MEDFileSpeCls(const char *   file,
3907                 CORBA::Boolean overwrite,
3908                 CORBA::Long    version)
3909     :_file(file), _overwrite(overwrite), _version(version)
3910   {}
3911   std::string prepareMeshNameAndGroups(SMESH_Mesh_i& self)
3912   {
3913     return self.prepareMeshNameAndGroups(_file.c_str(),_overwrite);
3914   }
3915
3916   void exportTo(SMESH_Mesh *mesh, const std::string& aMeshName, CORBA::Boolean auto_groups,
3917                 SMESH_MeshPartDS* partDS, CORBA::Boolean autoDimension, bool have0dField,
3918                 CORBA::Double ZTolerance, CORBA::Boolean saveNumbers )
3919   {
3920     mesh->ExportMED( _file.c_str(), aMeshName.c_str(), auto_groups, _version,
3921                      partDS, autoDimension, have0dField, ZTolerance, saveNumbers );
3922   }
3923
3924   void exportField(SMESH_Mesh_i& self, const std::string& aMeshName, bool have0dField,
3925                    SMESHDS_Mesh *meshDS, const GEOM::ListOfFields& fields,
3926                    const char*geomAssocFields)
3927   {
3928     DriverMED_W_Field fieldWriter;
3929     fieldWriter.SetFile( _file.c_str() );
3930     fieldWriter.SetMeshName( aMeshName );
3931     fieldWriter.AddODOnVertices( have0dField );
3932     self.exportMEDFields( fieldWriter, meshDS, fields, geomAssocFields );
3933   }
3934
3935   void prepareForWriting(SMESH_Mesh_i& self) { self.PrepareForWriting(_file.c_str(), _overwrite); }
3936
3937 private:
3938   std::string    _file;
3939   CORBA::Boolean _overwrite;
3940   CORBA::Long    _version;
3941 };
3942
3943 //================================================================================
3944 /*!
3945  * \brief Export a part of mesh to a med file
3946  */
3947 //================================================================================
3948
3949 template<class SPECLS>
3950 void SMESH_Mesh_i::ExportPartToMEDCommon(SPECLS&                   speCls,
3951                                          SMESH::SMESH_IDSource_ptr meshPart,
3952                                          CORBA::Boolean            auto_groups,
3953                                          CORBA::Boolean            autoDimension,
3954                                          const GEOM::ListOfFields& fields,
3955                                          const char*               geomAssocFields,
3956                                          CORBA::Double             ZTolerance,
3957                                          CORBA::Boolean            saveNumbers)
3958 {
3959   SMESH_TRY;
3960   if ( _preMeshInfo )
3961     _preMeshInfo->FullLoadFromFile();
3962
3963   // check fields
3964   bool have0dField = false;
3965   if ( fields.length() > 0 )
3966   {
3967     GEOM::GEOM_Object_var shapeToMesh = GetShapeToMesh();
3968     if ( shapeToMesh->_is_nil() )
3969       THROW_SALOME_CORBA_EXCEPTION( "No shape to mesh", SALOME::INTERNAL_ERROR );
3970
3971     for ( size_t i = 0; i < fields.length(); ++i )
3972     {
3973       if ( fields[i]->GetDataType() == GEOM::FDT_String )
3974         THROW_SALOME_CORBA_EXCEPTION
3975           ( "Export of string fields is not supported", SALOME::BAD_PARAM);
3976       GEOM::GEOM_Object_var fieldShape = fields[i]->GetShape();
3977       if ( fieldShape->_is_nil() )
3978         THROW_SALOME_CORBA_EXCEPTION( "Null shape under a field", SALOME::INTERNAL_ERROR );
3979       if ( !fieldShape->IsSame( shapeToMesh ) )
3980         THROW_SALOME_CORBA_EXCEPTION( "Field defined not on shape", SALOME::BAD_PARAM);
3981       if ( fields[i]->GetDimension() == 0 )
3982         have0dField = true;
3983     }
3984     if ( geomAssocFields )
3985       for ( int i = 0; geomAssocFields[i]; ++i )
3986         switch ( geomAssocFields[i] ) {
3987         case 'v':case 'e':case 'f':case 's': break;
3988         case 'V':case 'E':case 'F':case 'S': break;
3989         default: THROW_SALOME_CORBA_EXCEPTION
3990             ( "geomAssocFields can include only [vefs] characters", SALOME::BAD_PARAM);
3991         }
3992   }
3993
3994   SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
3995
3996   // write mesh
3997
3998   string aMeshName = "Mesh";
3999   SMESHUtils::Deleter< SMESH_MeshPartDS > tmpDSDeleter(0);
4000   if ( CORBA::is_nil( meshPart ) ||
4001        SMESH::DownCast< SMESH_Mesh_i* >( meshPart ))
4002   {
4003     aMeshName = speCls.prepareMeshNameAndGroups(*this);
4004     speCls.exportTo(_impl, aMeshName, auto_groups, nullptr, autoDimension,
4005                     have0dField, ZTolerance, saveNumbers );
4006     meshDS = _impl->GetMeshDS();
4007   }
4008   else
4009   {
4010     if ( _preMeshInfo )
4011       _preMeshInfo->FullLoadFromFile();
4012
4013     speCls.prepareForWriting(*this);
4014
4015     SALOMEDS::SObject_wrap SO = _gen_i->ObjectToSObject( meshPart );
4016     if ( !SO->_is_nil() ) {
4017       CORBA::String_var name = SO->GetName();
4018       aMeshName = name;
4019     }
4020
4021     SMESH_MeshPartDS* partDS = new SMESH_MeshPartDS( meshPart );
4022     speCls.exportTo(_impl, aMeshName, auto_groups, partDS, autoDimension,
4023                     have0dField, ZTolerance, saveNumbers);
4024     meshDS = tmpDSDeleter._obj = partDS;
4025   }
4026
4027   // write fields
4028
4029   if ( _impl->HasShapeToMesh() )
4030   {
4031     speCls.exportField( *this, aMeshName, have0dField, meshDS, fields, geomAssocFields);
4032   }
4033   SMESH_CATCH( SMESH::throwCorbaException );
4034 }
4035
4036 //================================================================================
4037 /*!
4038  * \brief Export a part of mesh to a med file
4039  */
4040 //================================================================================
4041
4042 void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
4043                                    const char*               file,
4044                                    CORBA::Boolean            auto_groups,
4045                                    CORBA::Long               version,
4046                                    CORBA::Boolean            overwrite,
4047                                    CORBA::Boolean            autoDimension,
4048                                    const GEOM::ListOfFields& fields,
4049                                    const char*               geomAssocFields,
4050                                    CORBA::Double             ZTolerance,
4051                                    CORBA::Boolean            saveNumbers)
4052 {
4053   MESSAGE("MED version: "<< version);
4054
4055   MEDFileSpeCls spe( file, overwrite, version );
4056   this->ExportPartToMEDCommon( spe, meshPart, auto_groups, autoDimension, fields,
4057                                geomAssocFields, ZTolerance, saveNumbers );
4058   // dump
4059   SMESH_TRY;
4060   GEOM::ListOfGBO_var goList = new GEOM::ListOfGBO;
4061   goList->length( fields.length() );
4062   for ( size_t i = 0; i < fields.length(); ++i )
4063   {
4064     GEOM::GEOM_BaseObject_var gbo = GEOM::GEOM_BaseObject::_narrow( fields[i] );
4065     goList[i] = gbo;
4066   }
4067   TPythonDump() << _this() << ".ExportPartToMED( "
4068                 << meshPart << ", r'"
4069                 << file << "', "
4070                 << auto_groups << ", "
4071                 << version << ", "
4072                 << overwrite << ", "
4073                 << autoDimension << ", "
4074                 << goList << ", '"
4075                 << ( geomAssocFields ? geomAssocFields : "" ) << "',"
4076                 << TVar( ZTolerance ) << ", "
4077                 << saveNumbers
4078                 << " )";
4079   SMESH_CATCH( SMESH::throwCorbaException );
4080 }
4081
4082 //================================================================================
4083
4084 class MEDFileMemSpeCls
4085 {
4086 public:
4087   std::string prepareMeshNameAndGroups(SMESH_Mesh_i& self) { return self.generateMeshName(); }
4088
4089   void exportTo(SMESH_Mesh *mesh, const std::string& aMeshName, CORBA::Boolean auto_groups,
4090                 SMESH_MeshPartDS* partDS, CORBA::Boolean autoDimension, bool have0dField,
4091                 CORBA::Double ZTolerance, CORBA::Boolean saveNumbers )
4092   {
4093     _res = mesh->ExportMEDCoupling(aMeshName.c_str(), auto_groups, partDS,
4094                                    autoDimension, have0dField, ZTolerance, saveNumbers );
4095   }
4096   void prepareForWriting(SMESH_Mesh_i& /*self*/) { /* nothing here */ }
4097
4098   void exportField(SMESH_Mesh_i& self, const std::string& aMeshName, bool have0dField,
4099                    SMESHDS_Mesh *meshDS, const GEOM::ListOfFields& fields,
4100                    const char*geomAssocFields)
4101   {
4102     DriverMED_W_Field_Mem fieldWriter(_res);
4103     fieldWriter.SetMeshName( aMeshName );
4104     fieldWriter.AddODOnVertices( have0dField );
4105     self.exportMEDFields( fieldWriter, meshDS, fields, geomAssocFields );
4106     _res = fieldWriter.getData();
4107   }
4108 public:
4109   MEDCoupling::MCAuto<MEDCoupling::DataArrayByte> getData() { return _res; }
4110
4111 private:
4112   MEDCoupling::MCAuto<MEDCoupling::DataArrayByte> _res;
4113 };
4114
4115 //================================================================================
4116 /*!
4117  * \brief Export a part of mesh to a MEDCoupling DS
4118  */
4119 //================================================================================
4120
4121 CORBA::LongLong SMESH_Mesh_i::ExportPartToMEDCoupling(SMESH::SMESH_IDSource_ptr meshPart,
4122                                                       CORBA::Boolean            auto_groups,
4123                                                       CORBA::Boolean            autoDimension,
4124                                                       const GEOM::ListOfFields& fields,
4125                                                       const char*               geomAssocFields,
4126                                                       CORBA::Double             ZTolerance,
4127                                                       CORBA::Boolean            saveNumbers)
4128 {
4129   MEDCoupling::MCAuto<MEDCoupling::DataArrayByte> data;
4130
4131   SMESH_TRY;
4132   if( !this->_gen_i->isSSLMode() )
4133     SMESH::throwCorbaException("SMESH_Mesh_i::ExportPartToMEDCoupling : only for embedded mode !");
4134
4135   MEDFileMemSpeCls spe;
4136   this->ExportPartToMEDCommon( spe, meshPart, auto_groups, autoDimension, fields, geomAssocFields,
4137                                ZTolerance, saveNumbers );
4138   data = spe.getData();
4139
4140   SMESH_CATCH( SMESH::throwCorbaException );
4141
4142   MEDCoupling::DataArrayByte *ret(data.retn());
4143   return reinterpret_cast<CORBA::LongLong>(ret);
4144 }
4145
4146 //================================================================================
4147 /*!
4148  * Write GEOM fields to MED file
4149  */
4150 //================================================================================
4151
4152 void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
4153                                     SMESHDS_Mesh*             meshDS,
4154                                     const GEOM::ListOfFields& fields,
4155                                     const char*               geomAssocFields)
4156 {
4157 #define METH "SMESH_Mesh_i::exportMEDFields() "
4158
4159   if (( fields.length() < 1 ) &&
4160       ( !geomAssocFields || !geomAssocFields[0] ))
4161     return;
4162
4163   std::vector< std::vector< double > > dblVals;
4164   std::vector< std::vector< int > >    intVals;
4165   std::vector< int >                   subIdsByDim[ 4 ];
4166   const double noneDblValue = 0.;
4167   const double noneIntValue = 0;
4168
4169   for ( size_t iF = 0; iF < fields.length(); ++iF )
4170   {
4171     // set field data
4172
4173     int dim = fields[ iF ]->GetDimension();
4174     SMDSAbs_ElementType elemType;
4175     TopAbs_ShapeEnum    shapeType;
4176     switch ( dim ) {
4177     case 0: elemType = SMDSAbs_0DElement; shapeType = TopAbs_VERTEX; break;
4178     case 1: elemType = SMDSAbs_Edge;      shapeType = TopAbs_EDGE;   break;
4179     case 2: elemType = SMDSAbs_Face;      shapeType = TopAbs_FACE;   break;
4180     case 3: elemType = SMDSAbs_Volume;    shapeType = TopAbs_SOLID;  break;
4181     default:
4182       continue; // skip fields on whole shape
4183     }
4184     GEOM::field_data_type dataType = fields[ iF ]->GetDataType();
4185     if ( dataType == GEOM::FDT_String )
4186       continue;
4187     GEOM::ListOfLong_var stepIDs = fields[ iF ]->GetSteps();
4188     if ( stepIDs->length() < 1 )
4189       continue;
4190     GEOM::string_array_var comps = fields[ iF ]->GetComponents();
4191     if ( comps->length() < 1 )
4192       continue;
4193     CORBA::String_var       name = fields[ iF ]->GetName();
4194
4195     if ( !fieldWriter.Set( meshDS,
4196                            name.in(),
4197                            elemType,
4198                            comps->length(),
4199                            /*isIntData=*/false ))//( dataType == GEOM::FDT_Int )))
4200       continue;
4201
4202     for ( size_t iC = 0; iC < comps->length(); ++iC )
4203       fieldWriter.SetCompName( iC, comps[ iC ].in() );
4204
4205     dblVals.resize( comps->length() );
4206     intVals.resize( comps->length() );
4207
4208     // find sub-shape IDs
4209
4210     std::vector< int >& subIds = subIdsByDim[ dim ];
4211     if ( subIds.empty() )
4212       for ( int id = 1; id <= meshDS->MaxShapeIndex(); ++id )
4213         if ( meshDS->IndexToShape( id ).ShapeType() == shapeType )
4214           subIds.push_back( id );
4215
4216     // write steps
4217
4218     SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
4219     if ( !elemIt )
4220       continue;
4221
4222     for ( size_t iS = 0; iS < stepIDs->length(); ++iS )
4223     {
4224       GEOM::GEOM_FieldStep_var step = fields[ iF ]->GetStep( stepIDs[ iS ]);
4225       if ( step->_is_nil() )
4226         continue;
4227
4228       CORBA::Long stamp = step->GetStamp();
4229       CORBA::Long id    = step->GetID();
4230       fieldWriter.SetDtIt( int( stamp ), int( id ));
4231
4232       // fill dblVals or intVals
4233       for ( size_t iC = 0; iC < comps->length(); ++iC )
4234         if ( dataType == GEOM::FDT_Double )
4235         {
4236           dblVals[ iC ].clear();
4237           dblVals[ iC ].resize( meshDS->MaxShapeIndex()+1, 0 );
4238         }
4239         else
4240         {
4241           intVals[ iC ].clear();
4242           intVals[ iC ].resize( meshDS->MaxShapeIndex()+1, 0 );
4243         }
4244       switch ( dataType )
4245       {
4246       case GEOM::FDT_Double:
4247       {
4248         GEOM::GEOM_DoubleFieldStep_var dblStep = GEOM::GEOM_DoubleFieldStep::_narrow( step );
4249         if ( dblStep->_is_nil() ) continue;
4250         GEOM::ListOfDouble_var vv = dblStep->GetValues();
4251         if ( vv->length() != subIds.size() * comps->length() )
4252           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
4253         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
4254           for ( size_t iC = 0; iC < comps->length(); ++iC )
4255             dblVals[ iC ][ subIds[ iS ]] = vv[ iV++ ];
4256         break;
4257       }
4258       case GEOM::FDT_Int:
4259       {
4260         GEOM::GEOM_IntFieldStep_var intStep = GEOM::GEOM_IntFieldStep::_narrow( step );
4261         if ( intStep->_is_nil() ) continue;
4262         GEOM::ListOfLong_var vv = intStep->GetValues();
4263         if ( vv->length() != subIds.size() * comps->length() )
4264           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
4265         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
4266           for ( size_t iC = 0; iC < comps->length(); ++iC )
4267             intVals[ iC ][ subIds[ iS ]] = (int) vv[ iV++ ];
4268         break;
4269       }
4270       case GEOM::FDT_Bool:
4271       {
4272         GEOM::GEOM_BoolFieldStep_var boolStep = GEOM::GEOM_BoolFieldStep::_narrow( step );
4273         if ( boolStep->_is_nil() ) continue;
4274         GEOM::short_array_var vv = boolStep->GetValues();
4275         if ( vv->length() != subIds.size() * comps->length() )
4276           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
4277         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
4278           for ( size_t iC = 0; iC < comps->length(); ++iC )
4279             intVals[ iC ][ subIds[ iS ]] = (int) vv[ iV++ ];
4280         break;
4281       }
4282       default: continue;
4283       }
4284
4285       // pass values to fieldWriter
4286       elemIt = fieldWriter.GetOrderedElems();
4287       if ( dataType == GEOM::FDT_Double )
4288         while ( elemIt->more() )
4289         {
4290           const SMDS_MeshElement* e = elemIt->next();
4291           const int shapeID = e->getshapeId();
4292           if ( shapeID < 1 || shapeID >= (int) dblVals[0].size() )
4293             for ( size_t iC = 0; iC < comps->length(); ++iC )
4294               fieldWriter.AddValue( noneDblValue );
4295           else
4296             for ( size_t iC = 0; iC < comps->length(); ++iC )
4297               fieldWriter.AddValue( dblVals[ iC ][ shapeID ]);
4298         }
4299       else
4300         while ( elemIt->more() )
4301         {
4302           const SMDS_MeshElement* e = elemIt->next();
4303           const int shapeID = e->getshapeId();
4304           if ( shapeID < 1 || shapeID >= (int) intVals[0].size() )
4305             for ( size_t iC = 0; iC < comps->length(); ++iC )
4306               fieldWriter.AddValue( (double) noneIntValue );
4307           else
4308             for ( size_t iC = 0; iC < comps->length(); ++iC )
4309               fieldWriter.AddValue( (double) intVals[ iC ][ shapeID ]);
4310         }
4311
4312       // write a step
4313       fieldWriter.Perform();
4314       SMESH_ComputeErrorPtr res = fieldWriter.GetError();
4315       if ( res && res->IsKO() )
4316       {
4317         if ( res->myComment.empty() )
4318         { THROW_SALOME_CORBA_EXCEPTION( METH "Fatal error", SALOME::INTERNAL_ERROR ); }
4319         else
4320         { THROW_SALOME_CORBA_EXCEPTION( res->myComment.c_str(), SALOME::INTERNAL_ERROR ); }
4321       }
4322
4323     } // loop on steps
4324   } // loop on fields
4325
4326   if ( !geomAssocFields || !geomAssocFields[0] )
4327     return;
4328
4329   // write geomAssocFields
4330
4331   std::vector< int > shapeDim( TopAbs_SHAPE + 1 );
4332   shapeDim[ TopAbs_COMPOUND  ] = 3;
4333   shapeDim[ TopAbs_COMPSOLID ] = 3;
4334   shapeDim[ TopAbs_SOLID     ] = 3;
4335   shapeDim[ TopAbs_SHELL     ] = 2;
4336   shapeDim[ TopAbs_FACE      ] = 2;
4337   shapeDim[ TopAbs_WIRE      ] = 1;
4338   shapeDim[ TopAbs_EDGE      ] = 1;
4339   shapeDim[ TopAbs_VERTEX    ] = 0;
4340   shapeDim[ TopAbs_SHAPE     ] = 3;
4341
4342   for ( int iF = 0; geomAssocFields[ iF ]; ++iF )
4343   {
4344     std::vector< std::string > compNames;
4345     switch ( geomAssocFields[ iF ]) {
4346     case 'v': case 'V':
4347       fieldWriter.Set( meshDS, "_vertices_", SMDSAbs_Node, /*nbComps=*/2, /*isInt=*/false );
4348       compNames.push_back( "dim" );
4349       break;
4350     case 'e': case 'E':
4351       fieldWriter.Set( meshDS, "_edges_", SMDSAbs_Edge, /*nbComps=*/1, /*isInt=*/false );
4352       break;
4353     case 'f': case 'F':
4354       fieldWriter.Set( meshDS, "_faces_", SMDSAbs_Face, /*nbComps=*/1, /*isInt=*/false );
4355       break;
4356     case 's': case 'S':
4357       fieldWriter.Set( meshDS, "_solids_", SMDSAbs_Volume, /*nbComps=*/1, /*isInt=*/false );
4358       break;
4359     default: continue;
4360     }
4361     compNames.push_back( "id" );
4362     for ( size_t iC = 0; iC < compNames.size(); ++iC )
4363       fieldWriter.SetCompName( iC, compNames[ iC ].c_str() );
4364
4365     fieldWriter.SetDtIt( -1, -1 );
4366
4367     SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
4368     if ( !elemIt )
4369       continue;
4370
4371     if ( compNames.size() == 2 ) // _vertices_
4372       while ( elemIt->more() )
4373       {
4374         const SMDS_MeshElement* e = elemIt->next();
4375         const int shapeID = e->getshapeId();
4376         if ( shapeID < 1 )
4377         {
4378           fieldWriter.AddValue( (double) -1 );
4379           fieldWriter.AddValue( (double) -1 );
4380         }
4381         else
4382         {
4383           const TopoDS_Shape& S = meshDS->IndexToShape( shapeID );
4384           fieldWriter.AddValue( (double) ( S.IsNull() ? -1 : shapeDim[ S.ShapeType() ]));
4385           fieldWriter.AddValue( (double) shapeID );
4386         }
4387       }
4388     else
4389       while ( elemIt->more() )
4390       {
4391         const SMDS_MeshElement* e = elemIt->next();
4392         const int shapeID = e->getshapeId();
4393         if ( shapeID < 1 )
4394           fieldWriter.AddValue( (double) -1 );
4395         else
4396           fieldWriter.AddValue( (double) shapeID );
4397       }
4398
4399     // write a step
4400     fieldWriter.Perform();
4401     SMESH_ComputeErrorPtr res = fieldWriter.GetError();
4402     if ( res && res->IsKO() )
4403     {
4404       if ( res->myComment.empty() )
4405       { THROW_SALOME_CORBA_EXCEPTION( METH "Fatal error", SALOME::INTERNAL_ERROR ); }
4406       else
4407       { THROW_SALOME_CORBA_EXCEPTION( res->myComment.c_str(), SALOME::INTERNAL_ERROR ); }
4408     }
4409
4410   } // loop on geomAssocFields
4411
4412 #undef METH
4413 }
4414
4415 //================================================================================
4416 /*!
4417  * \brief Export a part of mesh to a DAT file
4418  */
4419 //================================================================================
4420
4421 void SMESH_Mesh_i::ExportPartToDAT(SMESH::SMESH_IDSource_ptr meshPart,
4422                                    const char*               file,
4423                                    CORBA::Boolean            renumber )
4424 {
4425   SMESH_TRY;
4426
4427   SMESH_MeshPartDS partDS( meshPart );
4428   _impl->ExportDAT( file, &partDS, renumber );
4429
4430   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
4431                 << ".ExportPartToDAT( " << meshPart << ", r'" << file << ", " << renumber << "' )";
4432
4433   SMESH_CATCH( SMESH::throwCorbaException );
4434 }
4435 //================================================================================
4436 /*!
4437  * \brief Export a part of mesh to an UNV file
4438  */
4439 //================================================================================
4440
4441 void SMESH_Mesh_i::ExportPartToUNV(SMESH::SMESH_IDSource_ptr meshPart,
4442                                    const char*               file,
4443                                    CORBA::Boolean            renumber)
4444 {
4445   SMESH_TRY;
4446   if ( _preMeshInfo )
4447     _preMeshInfo->FullLoadFromFile();
4448
4449   PrepareForWriting(file);
4450
4451   SMESH_MeshPartDS partDS( meshPart );
4452   _impl->ExportUNV(file, &partDS, renumber );
4453
4454   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
4455                 << ".ExportPartToUNV( " << meshPart<< ", r'" << file << ", " << renumber << "' )";
4456
4457   SMESH_CATCH( SMESH::throwCorbaException );
4458 }
4459 //================================================================================
4460 /*!
4461  * \brief Export a part of mesh to an STL file
4462  */
4463 //================================================================================
4464
4465 void SMESH_Mesh_i::ExportPartToSTL(::SMESH::SMESH_IDSource_ptr meshPart,
4466                                    const char*                 file,
4467                                    ::CORBA::Boolean            isascii)
4468 {
4469   SMESH_TRY;
4470   if ( _preMeshInfo )
4471     _preMeshInfo->FullLoadFromFile();
4472
4473   PrepareForWriting(file);
4474
4475   CORBA::String_var name;
4476   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( meshPart );
4477   if ( !so->_is_nil() )
4478     name = so->GetName();
4479
4480   SMESH_MeshPartDS partDS( meshPart );
4481   _impl->ExportSTL( file, isascii, name.in(), &partDS );
4482
4483   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportPartToSTL( "
4484                 << meshPart<< ", r'" << file << "', " << isascii << ")";
4485
4486   SMESH_CATCH( SMESH::throwCorbaException );
4487 }
4488
4489 //================================================================================
4490 /*!
4491  * \brief Export a part of mesh to an STL file
4492  */
4493 //================================================================================
4494
4495 void SMESH_Mesh_i::ExportCGNS(::SMESH::SMESH_IDSource_ptr meshPart,
4496                               const char*                 file,
4497                               CORBA::Boolean              overwrite,
4498                               CORBA::Boolean              groupElemsByType)
4499 {
4500 #ifdef WITH_CGNS
4501   SMESH_TRY;
4502   if ( _preMeshInfo )
4503     _preMeshInfo->FullLoadFromFile();
4504
4505   PrepareForWriting(file,overwrite);
4506
4507   std::string meshName("");
4508   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( meshPart );
4509   if ( !so->_is_nil() )
4510   {
4511     CORBA::String_var name = so->GetName();
4512     meshName = name.in();
4513   }
4514   SMESH_TRY;
4515
4516   SMESH_MeshPartDS partDS( meshPart );
4517   _impl->ExportCGNS(file, &partDS, meshName.c_str(), groupElemsByType );
4518
4519   SMESH_CATCH( SMESH::throwCorbaException );
4520
4521   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportCGNS( "
4522                 << meshPart<< ", r'" << file << "', " << overwrite << ")";
4523
4524   SMESH_CATCH( SMESH::throwCorbaException );
4525
4526 #else
4527   THROW_SALOME_CORBA_EXCEPTION("CGNS library is unavailable", SALOME::INTERNAL_ERROR);
4528 #endif
4529 }
4530
4531 //================================================================================
4532 /*!
4533  * \brief Export a part of mesh to a GMF file
4534  */
4535 //================================================================================
4536
4537 void SMESH_Mesh_i::ExportGMF(::SMESH::SMESH_IDSource_ptr meshPart,
4538                              const char*                 file,
4539                              bool                        withRequiredGroups)
4540 {
4541   SMESH_TRY;
4542   if ( _preMeshInfo )
4543     _preMeshInfo->FullLoadFromFile();
4544
4545   PrepareForWriting(file,/*overwrite=*/true);
4546
4547   SMESH_MeshPartDS partDS( meshPart );
4548   _impl->ExportGMF(file, &partDS, withRequiredGroups);
4549
4550   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportGMF( "
4551                 << meshPart<< ", r'"
4552                 << file << "', "
4553                 << withRequiredGroups << ")";
4554
4555   SMESH_CATCH( SMESH::throwCorbaException );
4556 }
4557
4558 //=============================================================================
4559 /*!
4560  * Return computation progress [0.,1]
4561  */
4562 //=============================================================================
4563
4564 CORBA::Double SMESH_Mesh_i::GetComputeProgress()
4565 {
4566   SMESH_TRY;
4567
4568   return _impl->GetComputeProgress();
4569
4570   SMESH_CATCH( SMESH::doNothing );
4571   return 0.;
4572 }
4573
4574 //================================================================================
4575 /*!
4576  * \brief Return nb of nodes
4577  */
4578 //================================================================================
4579
4580 SMESH::smIdType SMESH_Mesh_i::NbNodes()
4581 {
4582   Unexpect aCatch(SALOME_SalomeException);
4583   if ( _preMeshInfo )
4584     return _preMeshInfo->NbNodes();
4585
4586   return _impl->NbNodes();
4587 }
4588
4589 //================================================================================
4590 /*!
4591  * \brief Return nb of elements
4592  */
4593 //================================================================================
4594
4595 SMESH::smIdType SMESH_Mesh_i::NbElements()
4596 {
4597   Unexpect aCatch(SALOME_SalomeException);
4598   if ( _preMeshInfo )
4599     return _preMeshInfo->NbElements();
4600
4601   return Nb0DElements() + NbEdges() + NbFaces() + NbVolumes() + NbBalls();
4602 }
4603
4604 //================================================================================
4605 /*!
4606  * \brief Return nb of 0D elements
4607  */
4608 //================================================================================
4609
4610 SMESH::smIdType SMESH_Mesh_i::Nb0DElements()
4611 {
4612   Unexpect aCatch(SALOME_SalomeException);
4613   if ( _preMeshInfo )
4614     return _preMeshInfo->Nb0DElements();
4615
4616   return _impl->Nb0DElements();
4617 }
4618
4619 //================================================================================
4620 /*!
4621  * \brief Return nb of BALL elements
4622  */
4623 //================================================================================
4624
4625 SMESH::smIdType SMESH_Mesh_i::NbBalls()
4626 {
4627   Unexpect aCatch(SALOME_SalomeException);
4628   if ( _preMeshInfo )
4629     return _preMeshInfo->NbBalls();
4630
4631   return _impl->NbBalls();
4632 }
4633
4634 //================================================================================
4635 /*!
4636  * \brief Return nb of 1D elements
4637  */
4638 //================================================================================
4639
4640 SMESH::smIdType SMESH_Mesh_i::NbEdges()
4641 {
4642   Unexpect aCatch(SALOME_SalomeException);
4643   if ( _preMeshInfo )
4644     return _preMeshInfo->NbEdges();
4645
4646   return _impl->NbEdges();
4647 }
4648
4649 //================================================================================
4650 /*!
4651  * \brief Return nb of edges
4652  */
4653 //================================================================================
4654
4655 SMESH::smIdType SMESH_Mesh_i::NbEdgesOfOrder(SMESH::ElementOrder order)
4656 {
4657   Unexpect aCatch(SALOME_SalomeException);
4658   if ( _preMeshInfo )
4659     return _preMeshInfo->NbEdges( (SMDSAbs_ElementOrder) order );
4660
4661   return _impl->NbEdges( (SMDSAbs_ElementOrder) order);
4662 }
4663
4664 //================================================================================
4665 /*!
4666  * \brief Return nb of faces
4667  */
4668 //================================================================================
4669
4670 SMESH::smIdType SMESH_Mesh_i::NbFaces()
4671 {
4672   Unexpect aCatch(SALOME_SalomeException);
4673   if ( _preMeshInfo )
4674     return _preMeshInfo->NbFaces();
4675
4676   return _impl->NbFaces();
4677 }
4678
4679 //================================================================================
4680 /*!
4681  * \brief Return nb of tringles
4682  */
4683 //================================================================================
4684
4685 SMESH::smIdType SMESH_Mesh_i::NbTriangles()
4686 {
4687   Unexpect aCatch(SALOME_SalomeException);
4688   if ( _preMeshInfo )
4689     return _preMeshInfo->NbTriangles();
4690
4691   return _impl->NbTriangles();
4692 }
4693
4694 //================================================================================
4695 /*!
4696  * \brief Return nb of bi-quadratic triangles
4697  */
4698 //================================================================================
4699
4700 SMESH::smIdType SMESH_Mesh_i::NbBiQuadTriangles()
4701 {
4702   Unexpect aCatch(SALOME_SalomeException);
4703   if ( _preMeshInfo )
4704     return _preMeshInfo->NbBiQuadTriangles();
4705
4706   return _impl->NbBiQuadTriangles();
4707 }
4708
4709 SMESH::smIdType SMESH_Mesh_i::NbQuadrangles()
4710 {
4711   Unexpect aCatch(SALOME_SalomeException);
4712   if ( _preMeshInfo )
4713     return _preMeshInfo->NbQuadrangles();
4714
4715   return _impl->NbQuadrangles();
4716 }
4717
4718 SMESH::smIdType SMESH_Mesh_i::NbBiQuadQuadrangles()
4719 {
4720   Unexpect aCatch(SALOME_SalomeException);
4721   if ( _preMeshInfo )
4722     return _preMeshInfo->NbBiQuadQuadrangles();
4723
4724   return _impl->NbBiQuadQuadrangles();
4725 }
4726
4727 SMESH::smIdType SMESH_Mesh_i::NbPolygons()
4728 {
4729   Unexpect aCatch(SALOME_SalomeException);
4730   if ( _preMeshInfo )
4731     return _preMeshInfo->NbPolygons();
4732
4733   return _impl->NbPolygons();
4734 }
4735
4736 SMESH::smIdType SMESH_Mesh_i::NbPolygonsOfOrder(SMESH::ElementOrder order)
4737 {
4738   Unexpect aCatch(SALOME_SalomeException);
4739   if ( _preMeshInfo )
4740     return _preMeshInfo->NbPolygons((SMDSAbs_ElementOrder) order);
4741
4742   return _impl->NbPolygons((SMDSAbs_ElementOrder)order);
4743 }
4744
4745 SMESH::smIdType SMESH_Mesh_i::NbFacesOfOrder(SMESH::ElementOrder order)
4746 {
4747   Unexpect aCatch(SALOME_SalomeException);
4748   if ( _preMeshInfo )
4749     return _preMeshInfo->NbFaces( (SMDSAbs_ElementOrder) order );
4750
4751   return _impl->NbFaces( (SMDSAbs_ElementOrder) order);
4752 }
4753
4754 SMESH::smIdType SMESH_Mesh_i::NbTrianglesOfOrder(SMESH::ElementOrder order)
4755 {
4756   Unexpect aCatch(SALOME_SalomeException);
4757   if ( _preMeshInfo )
4758     return _preMeshInfo->NbTriangles( (SMDSAbs_ElementOrder) order );
4759
4760   return _impl->NbTriangles( (SMDSAbs_ElementOrder) order);
4761 }
4762
4763 SMESH::smIdType SMESH_Mesh_i::NbQuadranglesOfOrder(SMESH::ElementOrder order)
4764 {
4765   Unexpect aCatch(SALOME_SalomeException);
4766   if ( _preMeshInfo )
4767     return _preMeshInfo->NbQuadrangles( (SMDSAbs_ElementOrder) order );
4768
4769   return _impl->NbQuadrangles( (SMDSAbs_ElementOrder) order);
4770 }
4771
4772 //=============================================================================
4773
4774 SMESH::smIdType SMESH_Mesh_i::NbVolumes()
4775 {
4776   Unexpect aCatch(SALOME_SalomeException);
4777   if ( _preMeshInfo )
4778     return _preMeshInfo->NbVolumes();
4779
4780   return _impl->NbVolumes();
4781 }
4782
4783 SMESH::smIdType SMESH_Mesh_i::NbTetras()
4784 {
4785   Unexpect aCatch(SALOME_SalomeException);
4786   if ( _preMeshInfo )
4787     return _preMeshInfo->NbTetras();
4788
4789   return _impl->NbTetras();
4790 }
4791
4792 SMESH::smIdType SMESH_Mesh_i::NbHexas()
4793 {
4794   Unexpect aCatch(SALOME_SalomeException);
4795   if ( _preMeshInfo )
4796     return _preMeshInfo->NbHexas();
4797
4798   return _impl->NbHexas();
4799 }
4800
4801 SMESH::smIdType SMESH_Mesh_i::NbTriQuadraticHexas()
4802 {
4803   Unexpect aCatch(SALOME_SalomeException);
4804   if ( _preMeshInfo )
4805     return _preMeshInfo->NbTriQuadHexas();
4806
4807   return _impl->NbTriQuadraticHexas();
4808 }
4809
4810 SMESH::smIdType SMESH_Mesh_i::NbPyramids()
4811 {
4812   Unexpect aCatch(SALOME_SalomeException);
4813   if ( _preMeshInfo )
4814     return _preMeshInfo->NbPyramids();
4815
4816   return _impl->NbPyramids();
4817 }
4818
4819 SMESH::smIdType SMESH_Mesh_i::NbPrisms()
4820 {
4821   Unexpect aCatch(SALOME_SalomeException);
4822   if ( _preMeshInfo )
4823     return _preMeshInfo->NbPrisms();
4824
4825   return _impl->NbPrisms();
4826 }
4827
4828 SMESH::smIdType SMESH_Mesh_i::NbHexagonalPrisms()
4829 {
4830   Unexpect aCatch(SALOME_SalomeException);
4831   if ( _preMeshInfo )
4832     return _preMeshInfo->NbHexPrisms();
4833
4834   return _impl->NbHexagonalPrisms();
4835 }
4836
4837 SMESH::smIdType SMESH_Mesh_i::NbPolyhedrons()
4838 {
4839   Unexpect aCatch(SALOME_SalomeException);
4840   if ( _preMeshInfo )
4841     return _preMeshInfo->NbPolyhedrons();
4842
4843   return _impl->NbPolyhedrons();
4844 }
4845
4846 SMESH::smIdType SMESH_Mesh_i::NbVolumesOfOrder(SMESH::ElementOrder order)
4847 {
4848   Unexpect aCatch(SALOME_SalomeException);
4849   if ( _preMeshInfo )
4850     return _preMeshInfo->NbVolumes( (SMDSAbs_ElementOrder) order );
4851
4852   return _impl->NbVolumes( (SMDSAbs_ElementOrder) order);
4853 }
4854
4855 SMESH::smIdType SMESH_Mesh_i::NbTetrasOfOrder(SMESH::ElementOrder order)
4856 {
4857   Unexpect aCatch(SALOME_SalomeException);
4858   if ( _preMeshInfo )
4859     return _preMeshInfo->NbTetras( (SMDSAbs_ElementOrder) order);
4860
4861   return _impl->NbTetras( (SMDSAbs_ElementOrder) order);
4862 }
4863
4864 SMESH::smIdType SMESH_Mesh_i::NbHexasOfOrder(SMESH::ElementOrder order)
4865 {
4866   Unexpect aCatch(SALOME_SalomeException);
4867   if ( _preMeshInfo )
4868     return _preMeshInfo->NbHexas( (SMDSAbs_ElementOrder) order);
4869
4870   return _impl->NbHexas( (SMDSAbs_ElementOrder) order);
4871 }
4872
4873 SMESH::smIdType SMESH_Mesh_i::NbPyramidsOfOrder(SMESH::ElementOrder order)
4874 {
4875   Unexpect aCatch(SALOME_SalomeException);
4876   if ( _preMeshInfo )
4877     return _preMeshInfo->NbPyramids( (SMDSAbs_ElementOrder) order);
4878
4879   return _impl->NbPyramids( (SMDSAbs_ElementOrder) order);
4880 }
4881
4882 SMESH::smIdType SMESH_Mesh_i::NbPrismsOfOrder(SMESH::ElementOrder order)
4883 {
4884   Unexpect aCatch(SALOME_SalomeException);
4885   if ( _preMeshInfo )
4886     return _preMeshInfo->NbPrisms( (SMDSAbs_ElementOrder) order);
4887
4888   return _impl->NbPrisms( (SMDSAbs_ElementOrder) order);
4889 }
4890
4891 //=============================================================================
4892 /*!
4893  * Return nb of published sub-meshes
4894  */
4895 //=============================================================================
4896
4897 SMESH::smIdType SMESH_Mesh_i::NbSubMesh()
4898 {
4899   Unexpect aCatch(SALOME_SalomeException);
4900   return _mapSubMesh_i.size();
4901 }
4902
4903 //=============================================================================
4904 /*!
4905  * Dumps mesh into a string
4906  */
4907 //=============================================================================
4908
4909 char* SMESH_Mesh_i::Dump()
4910 {
4911   ostringstream os;
4912   _impl->Dump( os );
4913   return CORBA::string_dup( os.str().c_str() );
4914 }
4915
4916 //=============================================================================
4917 /*!
4918  * Method of SMESH_IDSource interface
4919  */
4920 //=============================================================================
4921
4922 SMESH::smIdType_array* SMESH_Mesh_i::GetIDs()
4923 {
4924   return GetElementsId();
4925 }
4926
4927 //=============================================================================
4928 /*!
4929  * Return ids of all elements
4930  */
4931 //=============================================================================
4932
4933 SMESH::smIdType_array* SMESH_Mesh_i::GetElementsId()
4934 {
4935   Unexpect aCatch(SALOME_SalomeException);
4936   if ( _preMeshInfo )
4937     _preMeshInfo->FullLoadFromFile();
4938
4939   SMESH::smIdType_array_var aResult = new SMESH::smIdType_array();
4940   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
4941
4942   if ( aSMESHDS_Mesh == NULL )
4943     return aResult._retn();
4944
4945   smIdType nbElements = NbElements();
4946   aResult->length( nbElements );
4947   SMDS_ElemIteratorPtr anIt = aSMESHDS_Mesh->elementsIterator();
4948   for ( smIdType i = 0, n = nbElements; i < n && anIt->more(); i++ )
4949     aResult[i] = anIt->next()->GetID();
4950
4951   return aResult._retn();
4952 }
4953
4954
4955 //=============================================================================
4956 /*!
4957  * Return ids of all elements of given type
4958  */
4959 //=============================================================================
4960
4961 SMESH::smIdType_array* SMESH_Mesh_i::GetElementsByType( SMESH::ElementType theElemType )
4962 {
4963   Unexpect aCatch(SALOME_SalomeException);
4964   if ( _preMeshInfo )
4965     _preMeshInfo->FullLoadFromFile();
4966
4967   SMESH::smIdType_array_var aResult = new SMESH::smIdType_array();
4968   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
4969
4970   if ( aSMESHDS_Mesh == NULL )
4971     return aResult._retn();
4972
4973   smIdType nbElements = NbElements();
4974
4975   // No sense in returning ids of elements along with ids of nodes:
4976   // when theElemType == SMESH::ALL, return node ids only if
4977   // there are no elements
4978   if ( theElemType == SMESH::NODE || (theElemType == SMESH::ALL && nbElements == 0) )
4979     return GetNodesId();
4980
4981   aResult->length( nbElements );
4982
4983   smIdType i = 0;
4984
4985   SMDS_ElemIteratorPtr anIt = aSMESHDS_Mesh->elementsIterator( (SMDSAbs_ElementType)theElemType );
4986   while ( i < nbElements && anIt->more() )
4987     aResult[i++] = anIt->next()->GetID();
4988
4989   aResult->length( i );
4990
4991   return aResult._retn();
4992 }
4993
4994 //=============================================================================
4995 /*!
4996  * Return ids of all nodes
4997  */
4998 //=============================================================================
4999
5000 SMESH::smIdType_array* SMESH_Mesh_i::GetNodesId()
5001 {
5002   Unexpect aCatch(SALOME_SalomeException);
5003   if ( _preMeshInfo )
5004     _preMeshInfo->FullLoadFromFile();
5005
5006   SMESH::smIdType_array_var aResult = new SMESH::smIdType_array();
5007   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5008
5009   if ( aMeshDS == NULL )
5010     return aResult._retn();
5011
5012   smIdType nbNodes = NbNodes();
5013   aResult->length( nbNodes );
5014   SMDS_NodeIteratorPtr anIt = aMeshDS->nodesIterator();
5015   for ( smIdType i = 0, n = nbNodes; i < n && anIt->more(); i++ )
5016     aResult[i] = anIt->next()->GetID();
5017
5018   return aResult._retn();
5019 }
5020
5021 //=============================================================================
5022 /*!
5023  * Return type of the given element
5024  */
5025 //=============================================================================
5026
5027 SMESH::ElementType SMESH_Mesh_i::GetElementType( const SMESH::smIdType id, const bool iselem )
5028 {
5029   SMESH::ElementType type = SMESH::ALL;
5030   SMESH_TRY;
5031
5032   if ( _preMeshInfo )
5033     _preMeshInfo->FullLoadFromFile();
5034
5035   type = ( SMESH::ElementType ) _impl->GetElementType( id, iselem );
5036
5037   SMESH_CATCH( SMESH::throwCorbaException );
5038
5039   return type;
5040 }
5041
5042 //=============================================================================
5043 /*!
5044  * Return geometric type of the given element
5045  */
5046 //=============================================================================
5047
5048 SMESH::EntityType SMESH_Mesh_i::GetElementGeomType( const SMESH::smIdType id )
5049 {
5050   if ( _preMeshInfo )
5051     _preMeshInfo->FullLoadFromFile();
5052
5053   const SMDS_MeshElement* e = _impl->GetMeshDS()->FindElement(id);
5054   if ( !e )
5055     THROW_SALOME_CORBA_EXCEPTION( "invalid element id", SALOME::BAD_PARAM );
5056
5057   return ( SMESH::EntityType ) e->GetEntityType();
5058 }
5059
5060 //=============================================================================
5061 /*!
5062  * Return type of the given element
5063  */
5064 //=============================================================================
5065
5066 SMESH::GeometryType SMESH_Mesh_i::GetElementShape( const SMESH::smIdType id )
5067 {
5068   if ( _preMeshInfo )
5069     _preMeshInfo->FullLoadFromFile();
5070
5071   const SMDS_MeshElement* e = _impl->GetMeshDS()->FindElement(id);
5072   if ( !e )
5073     THROW_SALOME_CORBA_EXCEPTION( "invalid element id", SALOME::BAD_PARAM );
5074
5075   return ( SMESH::GeometryType ) e->GetGeomType();
5076 }
5077
5078 //=============================================================================
5079 /*!
5080  * Return ID of elements for given submesh
5081  */
5082 //=============================================================================
5083
5084 SMESH::smIdType_array* SMESH_Mesh_i::GetSubMeshElementsId(const CORBA::Long ShapeID)
5085 {
5086   SMESH::smIdType_array_var aResult = new SMESH::smIdType_array();
5087
5088   SMESH_TRY;
5089   if ( _preMeshInfo )
5090     _preMeshInfo->FullLoadFromFile();
5091
5092   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
5093   if(!SM) return aResult._retn();
5094
5095   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
5096   if(!SDSM) return aResult._retn();
5097
5098   aResult->length(SDSM->NbElements());
5099
5100   SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
5101   smIdType i = 0;
5102   while ( eIt->more() ) {
5103     aResult[i++] = eIt->next()->GetID();
5104   }
5105
5106   SMESH_CATCH( SMESH::throwCorbaException );
5107
5108   return aResult._retn();
5109 }
5110
5111 //=============================================================================
5112 /*!
5113  * Return ID of nodes for given sub-mesh
5114  * If param all==true - return all nodes, else -
5115  * Return only nodes on shapes.
5116  */
5117 //=============================================================================
5118
5119 SMESH::smIdType_array* SMESH_Mesh_i::GetSubMeshNodesId(const CORBA::Long ShapeID,
5120                                                    CORBA::Boolean    all)
5121 {
5122   SMESH::smIdType_array_var aResult = new SMESH::smIdType_array();
5123
5124   SMESH_TRY;
5125   if ( _preMeshInfo )
5126     _preMeshInfo->FullLoadFromFile();
5127
5128   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
5129   if(!SM) return aResult._retn();
5130
5131   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
5132   if(!SDSM) return aResult._retn();
5133
5134   set<smIdType> theElems;
5135   if( !all || (SDSM->NbElements()==0) ) { // internal nodes or vertex submesh
5136     SMDS_NodeIteratorPtr nIt = SDSM->GetNodes();
5137     while ( nIt->more() ) {
5138       const SMDS_MeshNode* elem = nIt->next();
5139       theElems.insert( elem->GetID() );
5140     }
5141   }
5142   else { // all nodes of submesh elements
5143     SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
5144     while ( eIt->more() ) {
5145       const SMDS_MeshElement* anElem = eIt->next();
5146       SMDS_ElemIteratorPtr nIt = anElem->nodesIterator();
5147       while ( nIt->more() ) {
5148         const SMDS_MeshElement* elem = nIt->next();
5149         theElems.insert( elem->GetID() );
5150       }
5151     }
5152   }
5153
5154   aResult->length(theElems.size());
5155   set<smIdType>::iterator itElem;
5156   smIdType i = 0;
5157   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5158     aResult[i++] = *itElem;
5159
5160   SMESH_CATCH( SMESH::throwCorbaException );
5161
5162   return aResult._retn();
5163 }
5164
5165 //=============================================================================
5166 /*!
5167  * Return type of elements for given sub-mesh
5168  */
5169 //=============================================================================
5170
5171 SMESH::ElementType SMESH_Mesh_i::GetSubMeshElementType(const CORBA::Long ShapeID)
5172 {
5173   SMESH::ElementType type = SMESH::ALL;
5174
5175   SMESH_TRY;
5176   if ( _preMeshInfo )
5177     _preMeshInfo->FullLoadFromFile();
5178
5179   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
5180   if(!SM) return SMESH::ALL;
5181
5182   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
5183   if(!SDSM) return SMESH::ALL;
5184
5185   if(SDSM->NbElements()==0)
5186     return (SM->GetSubShape().ShapeType() == TopAbs_VERTEX) ? SMESH::NODE : SMESH::ALL;
5187
5188   SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
5189   const SMDS_MeshElement* anElem = eIt->next();
5190
5191   type = ( SMESH::ElementType ) anElem->GetType();
5192
5193   SMESH_CATCH( SMESH::throwCorbaException );
5194
5195   return type;
5196 }
5197
5198
5199 //=============================================================================
5200 /*!
5201  * Return pointer to _impl as an integer value. Is called from constructor of SMESH_Client
5202  */
5203 //=============================================================================
5204
5205 CORBA::LongLong SMESH_Mesh_i::GetMeshPtr()
5206 {
5207   if ( _preMeshInfo )
5208     _preMeshInfo->FullLoadFromFile();
5209
5210   CORBA::LongLong pointeur = CORBA::LongLong(_impl);
5211   if ( MYDEBUG ) MESSAGE("CORBA::LongLong SMESH_Mesh_i::GetMeshPtr() "<<pointeur);
5212   return pointeur;
5213 }
5214
5215
5216 //=============================================================================
5217 /*!
5218  * Get XYZ coordinates of node as list of double
5219  * If there is not node for given ID - return empty list
5220  */
5221 //=============================================================================
5222
5223 SMESH::double_array* SMESH_Mesh_i::GetNodeXYZ(const SMESH::smIdType id)
5224 {
5225   if ( _preMeshInfo )
5226     _preMeshInfo->FullLoadFromFile();
5227
5228   SMESH::double_array_var aResult = new SMESH::double_array();
5229   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5230   if ( aMeshDS == NULL )
5231     return aResult._retn();
5232
5233   // find node
5234   const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
5235   if(!aNode)
5236     return aResult._retn();
5237
5238   // add coordinates
5239   aResult->length(3);
5240   aResult[0] = aNode->X();
5241   aResult[1] = aNode->Y();
5242   aResult[2] = aNode->Z();
5243   return aResult._retn();
5244 }
5245
5246
5247 //=============================================================================
5248 /*!
5249  * For given node return list of IDs of inverse elements
5250  * If there is not node for given ID - return empty list
5251  */
5252 //=============================================================================
5253
5254 SMESH::smIdType_array* SMESH_Mesh_i::GetNodeInverseElements(const SMESH::smIdType  id,
5255                                                             SMESH::ElementType elemType)
5256 {
5257   if ( _preMeshInfo )
5258     _preMeshInfo->FullLoadFromFile();
5259
5260   SMESH::smIdType_array_var aResult = new SMESH::smIdType_array();
5261   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5262   if ( aMeshDS == NULL )
5263     return aResult._retn();
5264
5265   // find node
5266   const SMDS_MeshNode* aNode = aMeshDS->FindNode( id );
5267   if ( !aNode )
5268     return aResult._retn();
5269
5270   // find inverse elements
5271   SMDSAbs_ElementType type = SMDSAbs_ElementType( elemType );
5272   SMDS_ElemIteratorPtr eIt = aNode->GetInverseElementIterator( type );
5273   aResult->length( aNode->NbInverseElements( type ));
5274   for( smIdType i = 0; eIt->more(); ++i )
5275   {
5276     const SMDS_MeshElement* elem = eIt->next();
5277     aResult[ i ] = elem->GetID();
5278   }
5279   return aResult._retn();
5280 }
5281
5282 //=============================================================================
5283 /*!
5284  * \brief Return position of a node on shape
5285  */
5286 //=============================================================================
5287
5288 SMESH::NodePosition* SMESH_Mesh_i::GetNodePosition(SMESH::smIdType NodeID)
5289 {
5290   if ( _preMeshInfo )
5291     _preMeshInfo->FullLoadFromFile();
5292
5293   SMESH::NodePosition* aNodePosition = new SMESH::NodePosition();
5294   aNodePosition->shapeID = 0;
5295   aNodePosition->shapeType = GEOM::SHAPE;
5296
5297   SMESHDS_Mesh* mesh = _impl->GetMeshDS();
5298   if ( !mesh ) return aNodePosition;
5299
5300   if ( const SMDS_MeshNode* aNode = mesh->FindNode(NodeID) )
5301   {
5302     if ( SMDS_PositionPtr pos = aNode->GetPosition() )
5303     {
5304       aNodePosition->shapeID = aNode->getshapeId();
5305       switch ( pos->GetTypeOfPosition() ) {
5306       case SMDS_TOP_EDGE:
5307         aNodePosition->shapeType = GEOM::EDGE;
5308         aNodePosition->params.length(1);
5309         aNodePosition->params[0] = SMDS_EdgePositionPtr( pos )->GetUParameter();
5310         break;
5311       case SMDS_TOP_FACE: {
5312         SMDS_FacePositionPtr fPos = pos;
5313         aNodePosition->shapeType = GEOM::FACE;
5314         aNodePosition->params.length(2);
5315         aNodePosition->params[0] = fPos->GetUParameter();
5316         aNodePosition->params[1] = fPos->GetVParameter();
5317         break;
5318       }
5319       case SMDS_TOP_VERTEX:
5320         aNodePosition->shapeType = GEOM::VERTEX;
5321         break;
5322       case SMDS_TOP_3DSPACE:
5323         if ( TopExp_Explorer(_impl->GetShapeToMesh(), TopAbs_SOLID).More() )
5324           aNodePosition->shapeType = GEOM::SOLID;
5325         else if ( TopExp_Explorer(_impl->GetShapeToMesh(), TopAbs_SHELL).More() )
5326           aNodePosition->shapeType = GEOM::SHELL;
5327         break;
5328       default:;
5329       }
5330     }
5331   }
5332   return aNodePosition;
5333 }
5334
5335 //=============================================================================
5336 /*!
5337  * \brief Return position of an element on shape
5338  */
5339 //=============================================================================
5340
5341 SMESH::ElementPosition SMESH_Mesh_i::GetElementPosition(SMESH::smIdType ElemID)
5342 {
5343   if ( _preMeshInfo )
5344     _preMeshInfo->FullLoadFromFile();
5345
5346   SMESH::ElementPosition anElementPosition;
5347   anElementPosition.shapeID = 0;
5348   anElementPosition.shapeType = GEOM::SHAPE;
5349
5350   SMESHDS_Mesh* mesh = _impl->GetMeshDS();
5351   if ( !mesh ) return anElementPosition;
5352
5353   if ( const SMDS_MeshElement* anElem = mesh->FindElement( ElemID ) )
5354   {
5355     anElementPosition.shapeID = anElem->getshapeId();
5356     const TopoDS_Shape& aSp = mesh->IndexToShape( anElem->getshapeId() );
5357     if ( !aSp.IsNull() ) {
5358       switch ( aSp.ShapeType() ) {
5359       case TopAbs_EDGE:
5360         anElementPosition.shapeType = GEOM::EDGE;
5361         break;
5362       case TopAbs_FACE:
5363         anElementPosition.shapeType = GEOM::FACE;
5364         break;
5365       case TopAbs_VERTEX:
5366         anElementPosition.shapeType = GEOM::VERTEX;
5367         break;
5368       case TopAbs_SOLID:
5369         anElementPosition.shapeType = GEOM::SOLID;
5370         break;
5371       case TopAbs_SHELL:
5372         anElementPosition.shapeType = GEOM::SHELL;
5373         break;
5374       default:;
5375       }
5376     }
5377   }
5378   return anElementPosition;
5379 }
5380
5381 //=============================================================================
5382 /*!
5383  * If given element is node return IDs of shape from position
5384  * If there is not node for given ID - return -1
5385  */
5386 //=============================================================================
5387
5388 CORBA::Long SMESH_Mesh_i::GetShapeID(const SMESH::smIdType id)
5389 {
5390   if ( _preMeshInfo )
5391     _preMeshInfo->FullLoadFromFile();
5392
5393   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5394   if ( aMeshDS == NULL )
5395     return -1;
5396
5397   // try to find node
5398   const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
5399   if(aNode) {
5400     return aNode->getshapeId();
5401   }
5402
5403   return -1;
5404 }
5405
5406
5407 //=============================================================================
5408 /*!
5409  * For given element return ID of result shape after
5410  * ::FindShape() from SMESH_MeshEditor
5411  * If there is not element for given ID - return -1
5412  */
5413 //=============================================================================
5414
5415 CORBA::Long SMESH_Mesh_i::GetShapeIDForElem(const SMESH::smIdType id)
5416 {
5417   if ( _preMeshInfo )
5418     _preMeshInfo->FullLoadFromFile();
5419
5420   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5421   if ( aMeshDS == NULL )
5422     return -1;
5423
5424   // try to find element
5425   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5426   if(!elem)
5427     return -1;
5428
5429   ::SMESH_MeshEditor aMeshEditor(_impl);
5430   int index = aMeshEditor.FindShape( elem );
5431   if(index>0)
5432     return index;
5433
5434   return -1;
5435 }
5436
5437
5438 //=============================================================================
5439 /*!
5440  * Return number of nodes for given element
5441  * If there is not element for given ID - return -1
5442  */
5443 //=============================================================================
5444
5445 CORBA::Short SMESH_Mesh_i::GetElemNbNodes(const SMESH::smIdType id)
5446 {
5447   if ( _preMeshInfo )
5448     _preMeshInfo->FullLoadFromFile();
5449
5450   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5451   if ( aMeshDS == NULL ) return -1;
5452   // try to find element
5453   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5454   if(!elem) return -1;
5455   return elem->NbNodes();
5456 }
5457
5458
5459 //=============================================================================
5460 /*!
5461  * Return ID of node by given index for given element
5462  * If there is not element for given ID - return -1
5463  * If there is not node for given index - return -2
5464  */
5465 //=============================================================================
5466
5467 SMESH::smIdType SMESH_Mesh_i::GetElemNode(const SMESH::smIdType id, const CORBA::Short index)
5468 {
5469   if ( _preMeshInfo )
5470     _preMeshInfo->FullLoadFromFile();
5471
5472   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5473   if ( aMeshDS == NULL ) return -1;
5474   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5475   if(!elem) return -1;
5476   if( index>=elem->NbNodes() || index<0 ) return -1;
5477   return elem->GetNode(index)->GetID();
5478 }
5479
5480 //=============================================================================
5481 /*!
5482  * Return IDs of nodes of given element
5483  */
5484 //=============================================================================
5485
5486 SMESH::smIdType_array* SMESH_Mesh_i::GetElemNodes(const SMESH::smIdType id)
5487 {
5488   if ( _preMeshInfo )
5489     _preMeshInfo->FullLoadFromFile();
5490
5491   SMESH::smIdType_array_var aResult = new SMESH::smIdType_array();
5492   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() )
5493   {
5494     if ( const SMDS_MeshElement* elem = aMeshDS->FindElement(id) )
5495     {
5496       aResult->length( elem->NbNodes() );
5497       for ( CORBA::ULong i = 0; i < aResult->length(); ++i )
5498         if ( const SMDS_MeshNode* n = elem->GetNode( i ))
5499           aResult[ i ] = n->GetID();
5500     }
5501   }
5502   return aResult._retn();
5503 }
5504
5505 //=============================================================================
5506 /*!
5507  * Return true if given node is medium node
5508  * in given quadratic element
5509  */
5510 //=============================================================================
5511
5512 CORBA::Boolean SMESH_Mesh_i::IsMediumNode(const SMESH::smIdType ide, const SMESH::smIdType idn)
5513 {
5514   if ( _preMeshInfo )
5515     _preMeshInfo->FullLoadFromFile();
5516
5517   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5518   if ( aMeshDS == NULL ) return false;
5519   // try to find node
5520   const SMDS_MeshNode* aNode = aMeshDS->FindNode(idn);
5521   if(!aNode) return false;
5522   // try to find element
5523   const SMDS_MeshElement* elem = aMeshDS->FindElement(ide);
5524   if(!elem) return false;
5525
5526   return elem->IsMediumNode(aNode);
5527 }
5528
5529
5530 //=============================================================================
5531 /*!
5532  * Return true if given node is medium node
5533  * in one of quadratic elements
5534  */
5535 //=============================================================================
5536
5537 CORBA::Boolean SMESH_Mesh_i::IsMediumNodeOfAnyElem(const SMESH::smIdType idn,
5538                                                    SMESH::ElementType theElemType)
5539 {
5540   if ( _preMeshInfo )
5541     _preMeshInfo->FullLoadFromFile();
5542
5543   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5544   if ( aMeshDS == NULL ) return false;
5545
5546   // try to find node
5547   const SMDS_MeshNode* aNode = aMeshDS->FindNode(idn);
5548   if(!aNode) return false;
5549
5550   SMESH_MesherHelper aHelper( *(_impl) );
5551
5552   SMDSAbs_ElementType aType;
5553   if(theElemType==SMESH::EDGE) aType = SMDSAbs_Edge;
5554   else if(theElemType==SMESH::FACE) aType = SMDSAbs_Face;
5555   else if(theElemType==SMESH::VOLUME) aType = SMDSAbs_Volume;
5556   else aType = SMDSAbs_All;
5557
5558   return aHelper.IsMedium(aNode,aType);
5559 }
5560
5561
5562 //=============================================================================
5563 /*!
5564  * Return number of edges for given element
5565  */
5566 //=============================================================================
5567
5568 CORBA::Long SMESH_Mesh_i::ElemNbEdges(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->NbEdges();
5578 }
5579
5580
5581 //=============================================================================
5582 /*!
5583  * Return number of faces for given element
5584  */
5585 //=============================================================================
5586
5587 CORBA::Long SMESH_Mesh_i::ElemNbFaces(const SMESH::smIdType id)
5588 {
5589   if ( _preMeshInfo )
5590     _preMeshInfo->FullLoadFromFile();
5591
5592   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5593   if ( aMeshDS == NULL ) return -1;
5594   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5595   if(!elem) return -1;
5596   return elem->NbFaces();
5597 }
5598
5599 //================================================================================
5600 /*!
5601  * \brief Return nodes of given face (counted from zero) for given element.
5602  */
5603 //================================================================================
5604
5605 SMESH::smIdType_array* SMESH_Mesh_i::GetElemFaceNodes(SMESH::smIdType  elemId,
5606                                                       CORBA::Short     faceIndex)
5607 {
5608   if ( _preMeshInfo )
5609     _preMeshInfo->FullLoadFromFile();
5610
5611   SMESH::smIdType_array_var aResult = new SMESH::smIdType_array();
5612   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() )
5613   {
5614     if ( const SMDS_MeshElement* elem = aMeshDS->FindElement(elemId) )
5615     {
5616       SMDS_VolumeTool vtool( elem, /*skipCentralNodes = */false );
5617       if ( faceIndex < vtool.NbFaces() )
5618       {
5619         aResult->length( vtool.NbFaceNodes( faceIndex ));
5620         const SMDS_MeshNode** nn = vtool.GetFaceNodes( faceIndex );
5621         for ( CORBA::ULong i = 0; i < aResult->length(); ++i )
5622           aResult[ i ] = nn[ i ]->GetID();
5623       }
5624     }
5625   }
5626   return aResult._retn();
5627 }
5628
5629 //================================================================================
5630 /*!
5631  * \brief Return three components of normal of given mesh face.
5632  */
5633 //================================================================================
5634
5635 SMESH::double_array* SMESH_Mesh_i::GetFaceNormal(CORBA::Long    elemId,
5636                                                  CORBA::Boolean normalized)
5637 {
5638   if ( _preMeshInfo )
5639     _preMeshInfo->FullLoadFromFile();
5640
5641   SMESH::double_array_var aResult = new SMESH::double_array();
5642
5643   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5644   {
5645     gp_XYZ normal;
5646     if ( SMESH_MeshAlgos::FaceNormal( mesh->FindElement(elemId), normal, normalized ))
5647     {
5648       aResult->length( 3 );
5649       aResult[ 0 ] = normal.X();
5650       aResult[ 1 ] = normal.Y();
5651       aResult[ 2 ] = normal.Z();
5652     }
5653   }
5654   return aResult._retn();
5655 }
5656
5657 //================================================================================
5658 /*!
5659  * \brief Return an element based on all given nodes.
5660  */
5661 //================================================================================
5662
5663 SMESH::smIdType SMESH_Mesh_i::FindElementByNodes(const SMESH::smIdType_array& nodes)
5664 {
5665   if ( _preMeshInfo )
5666     _preMeshInfo->FullLoadFromFile();
5667
5668   CORBA::Long elemID(0);
5669   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5670   {
5671     vector< const SMDS_MeshNode * > nn( nodes.length() );
5672     for ( CORBA::ULong i = 0; i < nodes.length(); ++i )
5673       if ( !( nn[i] = mesh->FindNode( nodes[i] )))
5674         return elemID;
5675
5676     const SMDS_MeshElement* elem = mesh->FindElement( nn, SMDSAbs_All, /*noMedium=*/false );
5677     if ( !elem && ( _impl->NbEdges  ( ORDER_QUADRATIC ) ||
5678                     _impl->NbFaces  ( ORDER_QUADRATIC ) ||
5679                     _impl->NbVolumes( ORDER_QUADRATIC )))
5680       elem = mesh->FindElement( nn, SMDSAbs_All, /*noMedium=*/true );
5681
5682     if ( elem ) elemID = CORBA::Long( elem->GetID() );
5683   }
5684   return elemID;
5685 }
5686
5687 //================================================================================
5688 /*!
5689  * \brief Return elements including all given nodes.
5690  */
5691 //================================================================================
5692
5693 SMESH::smIdType_array* SMESH_Mesh_i::GetElementsByNodes(const SMESH::smIdType_array& nodes,
5694                                                         SMESH::ElementType       elemType)
5695 {
5696   if ( _preMeshInfo )
5697     _preMeshInfo->FullLoadFromFile();
5698
5699   SMESH::smIdType_array_var result = new SMESH::smIdType_array();
5700
5701   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5702   {
5703     vector< const SMDS_MeshNode * > nn( nodes.length() );
5704     for ( CORBA::ULong i = 0; i < nodes.length(); ++i )
5705       nn[i] = mesh->FindNode( nodes[i] );
5706
5707     std::vector<const SMDS_MeshElement *> elems;
5708     mesh->GetElementsByNodes( nn, elems, (SMDSAbs_ElementType) elemType );
5709     result->length( elems.size() );
5710     for ( size_t i = 0; i < elems.size(); ++i )
5711       result[i] = elems[i]->GetID();
5712   }
5713   return result._retn();
5714 }
5715
5716 //=============================================================================
5717 /*!
5718  * Return true if given element is polygon
5719  */
5720 //=============================================================================
5721
5722 CORBA::Boolean SMESH_Mesh_i::IsPoly(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->IsPoly();
5732 }
5733
5734
5735 //=============================================================================
5736 /*!
5737  * Return true if given element is quadratic
5738  */
5739 //=============================================================================
5740
5741 CORBA::Boolean SMESH_Mesh_i::IsQuadratic(const SMESH::smIdType id)
5742 {
5743   if ( _preMeshInfo )
5744     _preMeshInfo->FullLoadFromFile();
5745
5746   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5747   if ( aMeshDS == NULL ) return false;
5748   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5749   if(!elem) return false;
5750   return elem->IsQuadratic();
5751 }
5752
5753 //=============================================================================
5754 /*!
5755  * Return diameter of ball discrete element or zero in case of an invalid \a id
5756  */
5757 //=============================================================================
5758
5759 CORBA::Double SMESH_Mesh_i::GetBallDiameter(SMESH::smIdType id)
5760 {
5761   if ( _preMeshInfo )
5762     _preMeshInfo->FullLoadFromFile();
5763
5764   if ( const SMDS_BallElement* ball =
5765        SMDS_Mesh::DownCast<SMDS_BallElement>( _impl->GetMeshDS()->FindElement( id )))
5766     return ball->GetDiameter();
5767
5768   return 0;
5769 }
5770
5771 //=============================================================================
5772 /*!
5773  * Return bary center for given element
5774  */
5775 //=============================================================================
5776
5777 SMESH::double_array* SMESH_Mesh_i::BaryCenter(const SMESH::smIdType id)
5778 {
5779   if ( _preMeshInfo )
5780     _preMeshInfo->FullLoadFromFile();
5781
5782   SMESH::double_array_var aResult = new SMESH::double_array();
5783   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5784   if ( aMeshDS == NULL )
5785     return aResult._retn();
5786
5787   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5788   if(!elem)
5789     return aResult._retn();
5790
5791   if(elem->GetType()==SMDSAbs_Volume) {
5792     SMDS_VolumeTool aTool;
5793     if(aTool.Set(elem)) {
5794       aResult->length(3);
5795       if (!aTool.GetBaryCenter( aResult[0], aResult[1], aResult[2]) )
5796         aResult->length(0);
5797     }
5798   }
5799   else {
5800     SMDS_ElemIteratorPtr anIt = elem->nodesIterator();
5801     int nbn = 0;
5802     double x=0., y=0., z=0.;
5803     for(; anIt->more(); ) {
5804       nbn++;
5805       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(anIt->next());
5806       x += aNode->X();
5807       y += aNode->Y();
5808       z += aNode->Z();
5809     }
5810     if(nbn>0) {
5811       // add coordinates
5812       aResult->length(3);
5813       aResult[0] = x/nbn;
5814       aResult[1] = y/nbn;
5815       aResult[2] = z/nbn;
5816     }
5817   }
5818
5819   return aResult._retn();
5820 }
5821
5822 //================================================================================
5823 /*!
5824  * \brief Create a group of elements preventing computation of a sub-shape
5825  */
5826 //================================================================================
5827
5828 SMESH::ListOfGroups*
5829 SMESH_Mesh_i::MakeGroupsOfBadInputElements( int         theSubShapeID,
5830                                             const char* theGroupName )
5831 {
5832   Unexpect aCatch(SALOME_SalomeException);
5833
5834   if ( !theGroupName || strlen( theGroupName) == 0 )
5835     THROW_SALOME_CORBA_EXCEPTION( "empty group name",SALOME::BAD_PARAM );
5836
5837   SMESH::ListOfGroups_var groups = new SMESH::ListOfGroups;
5838   ::SMESH_MeshEditor::ElemFeatures elemType;
5839
5840   // submesh by subshape id
5841   if ( !_impl->HasShapeToMesh() ) theSubShapeID = 1;
5842   if ( SMESH_subMesh * sm = _impl->GetSubMeshContaining( theSubShapeID ))
5843   {
5844     // compute error
5845     SMESH_ComputeErrorPtr error = sm->GetComputeError();
5846     if ( error && error->HasBadElems() )
5847     {
5848       // sort bad elements by type
5849       vector< const SMDS_MeshElement* > elemsByType[ SMDSAbs_NbElementTypes ];
5850       const list<const SMDS_MeshElement*>& badElems =
5851         static_cast<SMESH_BadInputElements*>( error.get() )->myBadElements;
5852       list<const SMDS_MeshElement*>::const_iterator elemIt  = badElems.begin();
5853       list<const SMDS_MeshElement*>::const_iterator elemEnd = badElems.end();
5854       for ( ; elemIt != elemEnd; ++elemIt )
5855       {
5856         const SMDS_MeshElement* elem = *elemIt;
5857         if ( !elem ) continue;
5858
5859         if ( elem->GetID() < 1 )
5860         {
5861           // elem is a temporary element, make a real element
5862           vector< const SMDS_MeshNode* > nodes;
5863           SMDS_NodeIteratorPtr nIt = elem->nodeIterator();
5864           while ( nIt->more() && elem )
5865           {
5866             nodes.push_back( nIt->next() );
5867             if ( nodes.back()->GetID() < 1 )
5868               elem = 0;  // a temporary element on temporary nodes
5869           }
5870           if ( elem )
5871           {
5872             ::SMESH_MeshEditor editor( _impl );
5873             elem = editor.AddElement( nodes, elemType.Init( elem ));
5874           }
5875         }
5876         if ( elem )
5877           elemsByType[ elem->GetType() ].push_back( elem );
5878       }
5879
5880       // how many groups to create?
5881       int nbTypes = 0;
5882       for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
5883         nbTypes += int( !elemsByType[ i ].empty() );
5884       groups->length( nbTypes );
5885
5886       // create groups
5887       for ( int i = 0, iG = -1; i < SMDSAbs_NbElementTypes; ++i )
5888       {
5889         vector< const SMDS_MeshElement* >& elems = elemsByType[ i ];
5890         if ( elems.empty() ) continue;
5891
5892         groups[ ++iG ] = createGroup( SMESH::ElementType(i), theGroupName );
5893         if ( _gen_i->CanPublishInStudy( groups[ iG ] ))
5894         {
5895           SMESH::SMESH_Mesh_var mesh = _this();
5896           SALOMEDS::SObject_wrap aSO =
5897             _gen_i->PublishGroup( mesh, groups[ iG ],
5898                                  GEOM::GEOM_Object::_nil(), theGroupName);
5899         }
5900         SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( groups[ iG ]);
5901         if ( !grp_i ) continue;
5902
5903         if ( SMESHDS_Group*  grpDS = dynamic_cast< SMESHDS_Group* >( grp_i->GetGroupDS() ))
5904           for ( size_t iE = 0; iE < elems.size(); ++iE )
5905             grpDS->SMDSGroup().Add( elems[ iE ]);
5906       }
5907     }
5908   }
5909
5910   return groups._retn();
5911 }
5912
5913 //=============================================================================
5914 /*!
5915  * Create and publish group servants if any groups were imported or created anyhow
5916  */
5917 //=============================================================================
5918
5919 void SMESH_Mesh_i::CreateGroupServants()
5920 {
5921   SMESH::SMESH_Mesh_var aMesh = _this();
5922
5923   set<int> addedIDs;
5924   ::SMESH_Mesh::GroupIteratorPtr groupIt = _impl->GetGroups();
5925   while ( groupIt->more() )
5926   {
5927     ::SMESH_Group* group = groupIt->next();
5928     int             anId = group->GetID();
5929
5930     map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.find(anId);
5931     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
5932       continue;
5933     addedIDs.insert( anId );
5934
5935     SMESH_GroupBase_i* aGroupImpl;
5936     TopoDS_Shape       shape;
5937     if ( SMESHDS_GroupOnGeom* groupOnGeom =
5938          dynamic_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() ))
5939     {
5940       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
5941       shape      = groupOnGeom->GetShape();
5942     }
5943     else {
5944       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
5945     }
5946
5947     SMESH::SMESH_GroupBase_var groupVar = aGroupImpl->_this();
5948     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( groupVar );
5949     aGroupImpl->Register();
5950
5951     // register CORBA object for persistence
5952     int nextId = _gen_i->RegisterObject( groupVar );
5953     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
5954     else        { (void)nextId; } // avoid "unused variable" warning in release mode
5955
5956     // publishing the groups in the study
5957     GEOM::GEOM_Object_var shapeVar = _gen_i->ShapeToGeomObject( shape );
5958     _gen_i->PublishGroup( aMesh, groupVar, shapeVar, group->GetName());
5959   }
5960
5961   if ( !addedIDs.empty() )
5962   {
5963     // python dump
5964     map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.begin();
5965     for ( int index = 0; i_grp != _mapGroups.end(); ++index, ++i_grp )
5966     {
5967       set<int>::iterator it = addedIDs.find( i_grp->first );
5968       if ( it != addedIDs.end() )
5969       {
5970         TPythonDump() << i_grp->second << " = " << aMesh << ".GetGroups()[ "<< index << " ]";
5971         addedIDs.erase( it );
5972         if ( addedIDs.empty() )
5973           break;
5974       }
5975     }
5976   }
5977 }
5978
5979 //=============================================================================
5980 /*!
5981  * \brief Return true if all sub-meshes are computed OK - to update an icon
5982  */
5983 //=============================================================================
5984
5985 bool SMESH_Mesh_i::IsComputedOK()
5986 {
5987   return _impl->IsComputedOK();
5988 }
5989
5990 //=============================================================================
5991 /*!
5992  * \brief Return groups cantained in _mapGroups by their IDs
5993  */
5994 //=============================================================================
5995
5996 SMESH::ListOfGroups* SMESH_Mesh_i::GetGroups(const list<int>& groupIDs) const
5997 {
5998   int nbGroups = groupIDs.size();
5999   SMESH::ListOfGroups_var aList = new SMESH::ListOfGroups();
6000   aList->length( nbGroups );
6001
6002   list<int>::const_iterator ids = groupIDs.begin();
6003   for ( nbGroups = 0; ids != groupIDs.end(); ++ids )
6004   {
6005     map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator it = _mapGroups.find( *ids );
6006     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
6007       aList[nbGroups++] = SMESH::SMESH_GroupBase::_duplicate( it->second );
6008   }
6009   aList->length( nbGroups );
6010   return aList._retn();
6011 }
6012
6013 //=============================================================================
6014 /*!
6015  * \brief Return information about imported file
6016  */
6017 //=============================================================================
6018
6019 SMESH::MedFileInfo* SMESH_Mesh_i::GetMEDFileInfo()
6020 {
6021   SMESH::MedFileInfo_var res( _medFileInfo );
6022   if ( !res.operator->() ) {
6023     res = new SMESH::MedFileInfo;
6024     res->fileName = "";
6025     res->fileSize = res->major = res->minor = res->release = -1;
6026   }
6027   return res._retn();
6028 }
6029
6030 //=======================================================================
6031 //function : FileInfoToString
6032 //purpose  : Persistence of file info
6033 //=======================================================================
6034
6035 std::string SMESH_Mesh_i::FileInfoToString()
6036 {
6037   std::string s;
6038   if ( &_medFileInfo.in() && _medFileInfo->fileName[0] )
6039   {
6040     s = SMESH_Comment( _medFileInfo->fileSize )
6041       << " " << _medFileInfo->major
6042       << " " << _medFileInfo->minor
6043       << " " << _medFileInfo->release
6044       << " " << _medFileInfo->fileName;
6045   }
6046   return s;
6047 }
6048
6049 //=======================================================================
6050 //function : FileInfoFromString
6051 //purpose  : Persistence of file info
6052 //=======================================================================
6053
6054 void SMESH_Mesh_i::FileInfoFromString(const std::string& info)
6055 {
6056   std::string size, major, minor, release, fileName;
6057   std::istringstream is(info);
6058   is >> size >> major >> minor >> release;
6059   fileName = info.data() + ( size.size()   + 1 +
6060                              major.size()  + 1 +
6061                              minor.size()  + 1 +
6062                              release.size()+ 1 );
6063
6064   _medFileInfo           = new SMESH::MedFileInfo();
6065   _medFileInfo->fileName = fileName.c_str();
6066   _medFileInfo->fileSize = atoi( size.c_str() );
6067   _medFileInfo->major    = atoi( major.c_str() );
6068   _medFileInfo->minor    = atoi( minor.c_str() );
6069   _medFileInfo->release  = atoi( release.c_str() );
6070 }
6071
6072 //=============================================================================
6073 /*!
6074  * \brief Pass names of mesh groups from study to mesh DS
6075  */
6076 //=============================================================================
6077
6078 void SMESH_Mesh_i::checkGroupNames()
6079 {
6080   int nbGrp = NbGroups();
6081   if ( !nbGrp )
6082     return;
6083
6084   SMESH::ListOfGroups* grpList = 0;
6085   // avoid dump of "GetGroups"
6086   {
6087     // store python dump into a local variable inside local scope
6088     SMESH::TPythonDump pDump; // do not delete this line of code
6089     grpList = GetGroups();
6090   }
6091
6092   for ( int gIndx = 0; gIndx < nbGrp; gIndx++ ) {
6093     SMESH::SMESH_GroupBase_ptr aGrp = (*grpList)[ gIndx ];
6094     if ( !aGrp )
6095       continue;
6096     SALOMEDS::SObject_wrap aGrpSO = _gen_i->ObjectToSObject( aGrp );
6097     if ( aGrpSO->_is_nil() )
6098       continue;
6099     // correct name of the mesh group if necessary
6100     const char* guiName = aGrpSO->GetName();
6101     if ( strcmp(guiName, aGrp->GetName()) )
6102       aGrp->SetName( guiName );
6103   }
6104 }
6105
6106 //=============================================================================
6107 /*!
6108  * \brief Set list of notebook variables used for Mesh operations separated by ":" symbol
6109  */
6110 //=============================================================================
6111 void SMESH_Mesh_i::SetParameters(const char* theParameters)
6112 {
6113   SMESH_Gen_i::GetSMESHGen()->UpdateParameters( CORBA::Object_var( _this() ).in(),
6114                                                 theParameters );
6115 }
6116
6117 //=============================================================================
6118 /*!
6119  * \brief Return list of notebook variables used for Mesh operations separated by ":" symbol
6120  */
6121 //=============================================================================
6122
6123 char* SMESH_Mesh_i::GetParameters()
6124 {
6125   return SMESH_Gen_i::GetSMESHGen()->GetParameters( SMESH::SMESH_Mesh_var( _this()) );
6126 }
6127
6128 //=============================================================================
6129 /*!
6130  * \brief Return list of notebook variables used for last Mesh operation
6131  */
6132 //=============================================================================
6133 SMESH::string_array* SMESH_Mesh_i::GetLastParameters()
6134 {
6135   SMESH::string_array_var aResult = new SMESH::string_array();
6136   SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen();
6137   if(gen) {
6138     CORBA::String_var aParameters = GetParameters();
6139     SALOMEDS::ListOfListOfStrings_var aSections = SMESH_Gen_i::GetSMESHGen()->getStudyServant()->ParseVariables(aParameters);
6140     if ( aSections->length() > 0 ) {
6141       SALOMEDS::ListOfStrings aVars = aSections[ aSections->length() - 1 ];
6142       aResult->length( aVars.length() );
6143       for ( CORBA::ULong i = 0;i < aVars.length(); i++ )
6144         aResult[i] = CORBA::string_dup( aVars[i] );
6145     }
6146   }
6147   return aResult._retn();
6148 }
6149
6150 //================================================================================
6151 /*!
6152  * \brief Return types of elements it contains
6153  */
6154 //================================================================================
6155
6156 SMESH::array_of_ElementType* SMESH_Mesh_i::GetTypes()
6157 {
6158   if ( _preMeshInfo )
6159     return _preMeshInfo->GetTypes();
6160
6161   SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType;
6162
6163   types->length( 5 );
6164   int nbTypes = 0;
6165   if (_impl->NbEdges())      types[nbTypes++] = SMESH::EDGE;
6166   if (_impl->NbFaces())      types[nbTypes++] = SMESH::FACE;
6167   if (_impl->NbVolumes())    types[nbTypes++] = SMESH::VOLUME;
6168   if (_impl->Nb0DElements()) types[nbTypes++] = SMESH::ELEM0D;
6169   if (_impl->NbBalls())      types[nbTypes++] = SMESH::BALL;
6170   if (_impl->NbNodes() &&
6171       nbTypes == 0 )         types[nbTypes++] = SMESH::NODE;
6172   types->length( nbTypes );
6173
6174   return types._retn();
6175 }
6176
6177 //================================================================================
6178 /*!
6179  * \brief Return self
6180  */
6181 //================================================================================
6182
6183 SMESH::SMESH_Mesh_ptr SMESH_Mesh_i::GetMesh()
6184 {
6185   return SMESH::SMESH_Mesh::_duplicate( _this() );
6186 }
6187
6188 //================================================================================
6189 /*!
6190  * \brief Return false if GetMeshInfo() return incorrect information that may
6191  *        happen if mesh data is not yet fully loaded from the file of study.
6192  * 
6193  * 
6194  */
6195 //================================================================================
6196
6197 bool SMESH_Mesh_i::IsMeshInfoCorrect()
6198 {
6199   return _preMeshInfo ? _preMeshInfo->IsMeshInfoCorrect() : true;
6200 }
6201
6202 //=============================================================================
6203 /*!
6204  * \brief Return number of mesh elements per each \a EntityType
6205  */
6206 //=============================================================================
6207
6208 SMESH::smIdType_array* SMESH_Mesh_i::GetMeshInfo()
6209 {
6210   if ( _preMeshInfo )
6211     return _preMeshInfo->GetMeshInfo();
6212
6213   SMESH::smIdType_array_var aRes = new SMESH::smIdType_array();
6214   aRes->length(SMESH::Entity_Last);
6215   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
6216     aRes[i] = 0;
6217   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
6218   if (!aMeshDS)
6219     return aRes._retn();
6220   const SMDS_MeshInfo& aMeshInfo = aMeshDS->GetMeshInfo();
6221   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
6222     aRes[i] = aMeshInfo.NbEntities((SMDSAbs_EntityType)i);
6223   return aRes._retn();
6224 }
6225
6226 //=============================================================================
6227 /*!
6228  * \brief Return number of mesh elements per each \a ElementType
6229  */
6230 //=============================================================================
6231
6232 SMESH::smIdType_array* SMESH_Mesh_i::GetNbElementsByType()
6233 {
6234   SMESH::smIdType_array_var aRes = new SMESH::smIdType_array();
6235   aRes->length(SMESH::NB_ELEMENT_TYPES);
6236   for (smIdType i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
6237     aRes[ i ] = 0;
6238
6239   const SMDS_MeshInfo* meshInfo = 0;
6240   if ( _preMeshInfo )
6241     meshInfo = _preMeshInfo;
6242   else if ( SMESHDS_Mesh* meshDS = _impl->GetMeshDS() )
6243     meshInfo = & meshDS->GetMeshInfo();
6244
6245   if (meshInfo)
6246     for (smIdType i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
6247       aRes[i] = meshInfo->NbElements((SMDSAbs_ElementType)i);
6248
6249   return aRes._retn();
6250 }
6251
6252 //=============================================================================
6253 /*
6254  * Collect statistic of mesh elements given by iterator
6255  */
6256 //=============================================================================
6257
6258 void SMESH_Mesh_i::CollectMeshInfo(const SMDS_ElemIteratorPtr theItr,
6259                                    SMESH::smIdType_array&     theInfo)
6260 {
6261   if (!theItr) return;
6262   while (theItr->more())
6263     theInfo[ theItr->next()->GetEntityType() ]++;
6264 }
6265 //=============================================================================
6266 /*
6267  * Return mesh unstructed grid information.
6268  */
6269 //=============================================================================
6270
6271 SALOMEDS::TMPFile* SMESH_Mesh_i::GetVtkUgStream()
6272 {
6273   SALOMEDS::TMPFile_var SeqFile;
6274   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() ) {
6275     SMDS_UnstructuredGrid* aGrid = aMeshDS->GetGrid();
6276     if(aGrid) {
6277       vtkUnstructuredGridWriter* aWriter = vtkUnstructuredGridWriter::New();
6278       aWriter->WriteToOutputStringOn();
6279       aWriter->SetInputData(aGrid);
6280       aWriter->SetFileTypeToBinary();
6281       aWriter->Write();
6282       char* str = aWriter->GetOutputString();
6283       int size = aWriter->GetOutputStringLength();
6284
6285       //Allocate octet buffer of required size
6286       CORBA::Octet* OctetBuf = SALOMEDS::TMPFile::allocbuf(size);
6287       //Copy ostrstream content to the octet buffer
6288       memcpy(OctetBuf, str, size);
6289       //Create and return TMPFile
6290       SeqFile = new SALOMEDS::TMPFile(size, size, OctetBuf, 1);
6291       aWriter->Delete();
6292     }
6293   }
6294   return SeqFile._retn();
6295 }
6296
6297 //=============================================================================
6298 namespace /* Iterators used in SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_var obj,
6299            *                                             SMESH::ElementType        type) */
6300 {
6301   using namespace SMESH::Controls;
6302   //-----------------------------------------------------------------------------
6303   struct PredicateIterator : public SMDS_ElemIterator
6304   {
6305     SMDS_ElemIteratorPtr    _elemIter;
6306     PredicatePtr            _predicate;
6307     const SMDS_MeshElement* _elem;
6308     SMDSAbs_ElementType     _type;
6309
6310     PredicateIterator( SMDS_ElemIteratorPtr iterator,
6311                        PredicatePtr         predicate,
6312                        SMDSAbs_ElementType  type):
6313       _elemIter(iterator), _predicate(predicate), _type(type)
6314     {
6315       next();
6316     }
6317     virtual bool more()
6318     {
6319       return _elem;
6320     }
6321     virtual const SMDS_MeshElement* next()
6322     {
6323       const SMDS_MeshElement* res = _elem;
6324       _elem = 0;
6325       while ( _elemIter->more() && !_elem )
6326       {
6327         if ((_elem = _elemIter->next()) &&
6328             (( _type != SMDSAbs_All && _type != _elem->GetType() ) ||
6329              ( !_predicate->IsSatisfy( _elem->GetID() ))))
6330           _elem = 0;
6331       }
6332       return res;
6333     }
6334   };
6335
6336   //-----------------------------------------------------------------------------
6337   struct IDSourceIterator : public SMDS_ElemIterator
6338   {
6339     const SMESH::smIdType*        _idPtr;
6340     const SMESH::smIdType*        _idEndPtr;
6341     SMESH::smIdType_array_var     _idArray;
6342     const SMDS_Mesh*              _mesh;
6343     const SMDSAbs_ElementType     _type;
6344     const SMDS_MeshElement*       _elem;
6345
6346     IDSourceIterator( const SMDS_Mesh*       mesh,
6347                       const SMESH::smIdType* ids,
6348                       const smIdType         nbIds,
6349                       SMDSAbs_ElementType    type):
6350       _idPtr( ids ), _idEndPtr( ids + nbIds ), _mesh( mesh ), _type( type ), _elem( 0 )
6351     {
6352       if ( _idPtr && nbIds && _mesh )
6353         next();
6354     }
6355     IDSourceIterator( const SMDS_Mesh*       mesh,
6356                       SMESH::smIdType_array* idArray,
6357                       SMDSAbs_ElementType    type):
6358       _idPtr( 0 ), _idEndPtr( 0 ), _idArray( idArray), _mesh( mesh ), _type( type ), _elem( 0 )
6359     {
6360       if ( idArray && _mesh )
6361       {
6362         _idPtr    = &_idArray[0];
6363         _idEndPtr = _idPtr + _idArray->length();
6364         next();
6365       }
6366     }
6367     virtual bool more()
6368     {
6369       return _elem;
6370     }
6371     virtual const SMDS_MeshElement* next()
6372     {
6373       const SMDS_MeshElement* res = _elem;
6374       _elem = 0;
6375       while ( _idPtr < _idEndPtr && !_elem )
6376       {
6377         if ( _type == SMDSAbs_Node )
6378         {
6379           _elem = _mesh->FindNode( *_idPtr++ );
6380         }
6381         else if ((_elem = _mesh->FindElement( *_idPtr++ )) &&
6382                  (_elem->GetType() != _type && _type != SMDSAbs_All ))
6383         {
6384           _elem = 0;
6385         }
6386       }
6387       return res;
6388     }
6389   };
6390   //-----------------------------------------------------------------------------
6391
6392   struct NodeOfElemIterator : public SMDS_ElemIterator
6393   {
6394     TColStd_MapOfInteger    _checkedNodeIDs;
6395     SMDS_ElemIteratorPtr    _elemIter;
6396     SMDS_ElemIteratorPtr    _nodeIter;
6397     const SMDS_MeshElement* _node;
6398
6399     NodeOfElemIterator( SMDS_ElemIteratorPtr iter ): _elemIter( iter ), _node( 0 )
6400     {
6401       if ( _elemIter && _elemIter->more() )
6402       {
6403         _nodeIter = _elemIter->next()->nodesIterator();
6404         next();
6405       }
6406     }
6407     virtual bool more()
6408     {
6409       return _node;
6410     }
6411     virtual const SMDS_MeshElement* next()
6412     {
6413       const SMDS_MeshElement* res = _node;
6414       _node = 0;
6415       while ( !_node && ( _elemIter->more() || _nodeIter->more() ))
6416       {
6417         if ( _nodeIter->more() )
6418         {
6419           _node = _nodeIter->next();
6420           if ( !_checkedNodeIDs.Add( _node->GetID() ))
6421             _node = 0;
6422         }
6423         else
6424         {
6425           _nodeIter = _elemIter->next()->nodesIterator();
6426         }
6427       }
6428       return res;
6429     }
6430   };
6431 }
6432
6433 //=============================================================================
6434 /*
6435  * Return iterator on elements of given type in given object
6436  */
6437 //=============================================================================
6438
6439 SMDS_ElemIteratorPtr SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_ptr theObject,
6440                                                SMESH::ElementType        theType)
6441 {
6442   SMDS_ElemIteratorPtr  elemIt;
6443   bool                  typeOK = ( theType == SMESH::ALL );
6444   SMDSAbs_ElementType elemType = SMDSAbs_ElementType( theType );
6445
6446   SMESH::SMESH_Mesh_var meshVar = theObject->GetMesh();
6447   SMESH_Mesh_i*          mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( meshVar );
6448   if ( !mesh_i ) return elemIt;
6449   SMESHDS_Mesh*          meshDS = mesh_i->GetImpl().GetMeshDS();
6450
6451   if ( SMESH::DownCast<SMESH_Mesh_i*>( theObject ))
6452   {
6453     elemIt = meshDS->elementsIterator( elemType );
6454     typeOK = true;
6455   }
6456   else if ( SMESH_subMesh_i* submesh_i = SMESH::DownCast<SMESH_subMesh_i*>( theObject ))
6457   {
6458     SMESHDS_SubMesh* sm = ((SMESHDS_Mesh*) meshDS)->MeshElements( submesh_i->GetId() );
6459     if ( sm )
6460     {
6461       elemIt = sm->GetElements();
6462       if ( elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
6463       {
6464         typeOK = ( elemIt && elemIt->more() && elemIt->next()->GetType() == elemType );
6465         elemIt = typeOK ? sm->GetElements() : SMDS_ElemIteratorPtr();
6466       }
6467     }
6468   }
6469   else if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( theObject ))
6470   {
6471     SMESHDS_GroupBase* groupDS = group_i->GetGroupDS();
6472     if ( groupDS && ( elemType == groupDS->GetType()  ||
6473                       elemType == SMDSAbs_Node ||
6474                       elemType == SMDSAbs_All ))
6475     {
6476       elemIt = groupDS->GetElements();
6477       typeOK = ( groupDS->GetType() == elemType || elemType == SMDSAbs_All );
6478     }
6479   }
6480   else if ( SMESH::Filter_i* filter_i = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
6481   {
6482     if ( filter_i->GetElementType() == theType ||
6483          filter_i->GetElementType() == SMESH::ALL ||
6484          elemType == SMDSAbs_Node ||
6485          elemType == SMDSAbs_All)
6486     {
6487       SMESH::Predicate_i* pred_i = filter_i->GetPredicate_i();
6488       if ( pred_i && pred_i->GetPredicate() )
6489       {
6490         SMDSAbs_ElementType filterType = SMDSAbs_ElementType( filter_i->GetElementType() );
6491         SMDS_ElemIteratorPtr allElemIt = meshDS->elementsIterator( filterType );
6492         SMDSAbs_ElementType   iterType = elemType == SMDSAbs_Node ? filterType : elemType;
6493         elemIt = SMDS_ElemIteratorPtr
6494           ( new PredicateIterator( allElemIt, pred_i->GetPredicate(), iterType ));
6495         typeOK = ( elemType == SMDSAbs_Node ? filterType == SMDSAbs_Node : elemIt->more() );
6496       }
6497     }
6498   }
6499   else
6500   {
6501     SMESH::array_of_ElementType_var types = theObject->GetTypes();
6502     const bool                    isNodes = ( types->length() == 1 && types[0] == SMESH::NODE );
6503     if ( isNodes && elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
6504       return elemIt;
6505     SMDSAbs_ElementType iterType = isNodes ? SMDSAbs_Node : elemType;
6506     if ( SMESH_MeshEditor_i::IsTemporaryIDSource( theObject ))
6507     {
6508       SMESH::smIdType nbIds;
6509       if ( SMESH::smIdType* ids = SMESH_MeshEditor_i::GetTemporaryIDs( theObject, nbIds ))
6510         elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids, nbIds, iterType ));
6511     }
6512     else
6513     {
6514       SMESH::smIdType_array_var ids = theObject->GetIDs();
6515       elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids._retn(), iterType ));
6516     }
6517     typeOK = ( isNodes == ( elemType == SMDSAbs_Node )) || ( elemType == SMDSAbs_All );
6518   }
6519
6520   if ( elemIt && elemIt->more() && !typeOK )
6521   {
6522     if ( elemType == SMDSAbs_Node )
6523     {
6524       elemIt = SMDS_ElemIteratorPtr( new NodeOfElemIterator( elemIt ));
6525     }
6526     else
6527     {
6528       elemIt = SMDS_ElemIteratorPtr();
6529     }
6530   }
6531   return elemIt;
6532 }
6533
6534 //=============================================================================
6535 namespace // Finding concurrent hypotheses
6536 //=============================================================================
6537 {
6538
6539 /*!
6540  * \brief mapping of mesh dimension into shape type
6541  */
6542 TopAbs_ShapeEnum shapeTypeByDim(const int theDim)
6543 {
6544   TopAbs_ShapeEnum aType = TopAbs_SOLID;
6545   switch ( theDim ) {
6546   case 0: aType = TopAbs_VERTEX; break;
6547   case 1: aType = TopAbs_EDGE; break;
6548   case 2: aType = TopAbs_FACE; break;
6549   case 3:
6550   default:aType = TopAbs_SOLID; break;
6551   }
6552   return aType;
6553 }
6554
6555 //-----------------------------------------------------------------------------
6556 /*!
6557  * \brief Internal structure used to find concurrent submeshes
6558  *
6559  * It represents a pair < submesh, concurrent dimension >, where
6560  * 'concurrent dimension' is dimension of shape where the submesh can concurrent
6561  *  with another submesh. In other words, it is dimension of a hypothesis assigned
6562  *  to submesh.
6563  */
6564 class SMESH_DimHyp
6565 {
6566  public:
6567   //! fields
6568   int _dim;    //!< a dimension the algo can build (concurrent dimension)
6569   int _ownDim; //!< dimension of shape of _subMesh (>=_dim)
6570   TopTools_MapOfShape  _shapeMap; //!< [sub-]shapes of dimension == _dim
6571   const SMESH_subMesh* _subMesh;
6572   list<const SMESHDS_Hypothesis*> _hypotheses; //!< algo is first, then its parameters
6573
6574   //-----------------------------------------------------------------------------
6575   // Return the algorithm
6576   const SMESH_Algo* GetAlgo() const
6577   { return _hypotheses.empty() ? 0 : dynamic_cast<const SMESH_Algo*>( _hypotheses.front() ); }
6578
6579   //-----------------------------------------------------------------------------
6580   //! Constructors
6581   SMESH_DimHyp(const SMESH_subMesh* theSubMesh,
6582                const int            theDim,
6583                const TopoDS_Shape&  theShape)
6584   {
6585     _subMesh = theSubMesh;
6586     SetShape( theDim, theShape );
6587   }
6588
6589   //-----------------------------------------------------------------------------
6590   //! set shape
6591   void SetShape(const int           theDim,
6592                 const TopoDS_Shape& theShape)
6593   {
6594     _dim = theDim;
6595     _ownDim = SMESH_Gen::GetShapeDim(theShape);
6596     if (_dim >= _ownDim)
6597       _shapeMap.Add( theShape );
6598     else {
6599       TopExp_Explorer anExp( theShape, shapeTypeByDim(theDim) );
6600       for( ; anExp.More(); anExp.Next() )
6601         _shapeMap.Add( anExp.Current() );
6602     }
6603   }
6604
6605   //-----------------------------------------------------------------------------
6606   //! Check sharing of sub-shapes
6607   static bool isShareSubShapes(const TopTools_MapOfShape& theToCheck,
6608                                const TopTools_MapOfShape& theToFind,
6609                                const TopAbs_ShapeEnum     theType)
6610   {
6611     bool isShared = false;
6612     TopTools_MapIteratorOfMapOfShape anItr( theToCheck );
6613     for (; !isShared && anItr.More(); anItr.Next() )
6614     {
6615       const TopoDS_Shape& aSubSh = anItr.Key();
6616       // check for case when concurrent dimensions are same
6617       isShared = theToFind.Contains( aSubSh );
6618       // check for sub-shape with concurrent dimension
6619       TopExp_Explorer anExp( aSubSh, theType );
6620       for ( ; !isShared && anExp.More(); anExp.Next() )
6621         isShared = theToFind.Contains( anExp.Current() );
6622     }
6623     return isShared;
6624   }
6625
6626   //-----------------------------------------------------------------------------
6627   //! check algorithms
6628   static bool checkAlgo(const SMESHDS_Hypothesis* theA1,
6629                         const SMESHDS_Hypothesis* theA2)
6630   {
6631     if ( !theA1 || !theA2 ||
6632          theA1->GetType() == SMESHDS_Hypothesis::PARAM_ALGO ||
6633          theA2->GetType() == SMESHDS_Hypothesis::PARAM_ALGO )
6634       return false; // one of the hypothesis is not algorithm
6635     // check algorithm names (should be equal)
6636     return strcmp( theA1->GetName(), theA2->GetName() ) == 0;
6637   }
6638
6639
6640   //-----------------------------------------------------------------------------
6641   //! Check if sub-shape hypotheses are concurrent
6642   bool IsConcurrent(const SMESH_DimHyp* theOther) const
6643   {
6644     if ( _subMesh == theOther->_subMesh )
6645       return false; // same sub-shape - should not be
6646
6647     // if ( <own dim of either of submeshes> == <concurrent dim> &&
6648     //      any of the two submeshes is not on COMPOUND shape )
6649     //  -> no concurrency
6650     bool meIsCompound    = (_subMesh->GetSubMeshDS() &&
6651                             _subMesh->GetSubMeshDS()->IsComplexSubmesh());
6652     bool otherIsCompound = (theOther->_subMesh->GetSubMeshDS() &&
6653                             theOther->_subMesh->GetSubMeshDS()->IsComplexSubmesh());
6654     if ( (_ownDim == _dim  || theOther->_ownDim == _dim ) && (!meIsCompound || !otherIsCompound))
6655       return false;
6656
6657     bool checkSubShape = isShareSubShapes( _shapeMap, theOther->_shapeMap, shapeTypeByDim(_dim));
6658     if ( !checkSubShape )
6659       return false;
6660
6661     // check algorithms to be same
6662     const SMESH_Algo* a1 = this->GetAlgo();
6663     const SMESH_Algo* a2 = theOther->GetAlgo();
6664     bool isSame = checkAlgo( a1, a2 );
6665     if ( !isSame )
6666     {
6667       return true;
6668       // commented off for IPAL54678
6669       // if ( !a1 || !a2 )
6670       //   return false; // pb?
6671       // return a1->GetDim() == a2->GetDim(); // different algorithms of same dim -> concurrency !
6672     }
6673
6674     // check hypothesises for concurrence (skip first as algorithm)
6675     size_t nbSame = 0;
6676     // pointers should be same, because it is referened from mesh hypothesis partition
6677     list <const SMESHDS_Hypothesis*>::const_iterator hypIt = _hypotheses.begin();
6678     list <const SMESHDS_Hypothesis*>::const_iterator otheEndIt = theOther->_hypotheses.end();
6679     for ( hypIt++ /*skip first as algo*/; hypIt != _hypotheses.end(); hypIt++ )
6680       if ( find( theOther->_hypotheses.begin(), otheEndIt, *hypIt ) != otheEndIt )
6681         nbSame++;
6682     // the submeshes are concurrent if their algorithms has different parameters
6683     return nbSame != theOther->_hypotheses.size() - 1;
6684   }
6685
6686   // Return true if algorithm of this SMESH_DimHyp is used if no
6687   // sub-mesh order is imposed by the user
6688   bool IsHigherPriorityThan( const SMESH_DimHyp* theOther ) const
6689   {
6690     // NeedDiscreteBoundary() algo has a higher priority
6691     if ( this    ->GetAlgo()->NeedDiscreteBoundary() !=
6692          theOther->GetAlgo()->NeedDiscreteBoundary() )
6693       return !this->GetAlgo()->NeedDiscreteBoundary();
6694
6695     return ( this->_subMesh->GetId() < theOther->_subMesh->GetId() );
6696   }
6697
6698 }; // end of SMESH_DimHyp
6699 //-----------------------------------------------------------------------------
6700
6701 typedef list<const SMESH_DimHyp*> TDimHypList;
6702
6703 //-----------------------------------------------------------------------------
6704
6705 void addDimHypInstance(const int                               theDim,
6706                        const TopoDS_Shape&                     theShape,
6707                        const SMESH_Algo*                       theAlgo,
6708                        const SMESH_subMesh*                    theSubMesh,
6709                        const list <const SMESHDS_Hypothesis*>& theHypList,
6710                        TDimHypList*                            theDimHypListArr )
6711 {
6712   if ( !theAlgo->NeedDiscreteBoundary() &&
6713        theAlgo->NeedLowerHyps( theDim )) // IPAL54678
6714     return;
6715   TDimHypList& listOfdimHyp = theDimHypListArr[theDim];
6716   if ( listOfdimHyp.empty() || listOfdimHyp.back()->_subMesh != theSubMesh )
6717   {
6718     SMESH_DimHyp* dimHyp = new SMESH_DimHyp( theSubMesh, theDim, theShape );
6719     dimHyp->_hypotheses.push_front(theAlgo);
6720     listOfdimHyp.push_back( dimHyp );
6721   }
6722
6723   SMESH_DimHyp* dimHyp = const_cast<SMESH_DimHyp*>( listOfdimHyp.back() );
6724   dimHyp->_hypotheses.insert( dimHyp->_hypotheses.end(),
6725                               theHypList.begin(), theHypList.end() );
6726 }
6727
6728 //-----------------------------------------------------------------------------
6729 void addInOrderOfPriority( const SMESH_DimHyp* theDimHyp,
6730                            TDimHypList&        theListOfConcurr)
6731 {
6732   if ( theListOfConcurr.empty() )
6733   {
6734     theListOfConcurr.push_back( theDimHyp );
6735   }
6736   else
6737   {
6738     TDimHypList::iterator hypIt = theListOfConcurr.begin();
6739     while ( hypIt != theListOfConcurr.end() &&
6740             !theDimHyp->IsHigherPriorityThan( *hypIt ))
6741       ++hypIt;
6742     theListOfConcurr.insert( hypIt, theDimHyp );
6743   }
6744 }
6745
6746 //-----------------------------------------------------------------------------
6747 void findConcurrents(const SMESH_DimHyp* theDimHyp,
6748                      const TDimHypList&  theListOfDimHyp,
6749                      TDimHypList&        theListOfConcurrHyp,
6750                      set<int>&           theSetOfConcurrId )
6751 {
6752   TDimHypList::const_reverse_iterator rIt = theListOfDimHyp.rbegin();
6753   for ( ; rIt != theListOfDimHyp.rend(); rIt++ )
6754   {
6755     const SMESH_DimHyp* curDimHyp = *rIt;
6756     if ( curDimHyp == theDimHyp )
6757       break; // meet own dimHyp pointer in same dimension
6758
6759     if ( theDimHyp->IsConcurrent( curDimHyp ) &&
6760          theSetOfConcurrId.insert( curDimHyp->_subMesh->GetId() ).second )
6761     {
6762       addInOrderOfPriority( curDimHyp, theListOfConcurrHyp );
6763     }
6764   }
6765 }
6766
6767 //-----------------------------------------------------------------------------
6768 bool unionLists(TListOfInt&       theListOfId,
6769                 TListOfListOfInt& theListOfListOfId,
6770                 const int         theIndx )
6771 {
6772   bool changed = false;
6773   if ( theListOfId.empty() )
6774     return changed;
6775   TListOfListOfInt::iterator it = theListOfListOfId.begin();
6776   for ( int i = 0; it != theListOfListOfId.end(); it++, i++ )
6777   {
6778     if ( i < theIndx )
6779       continue; //skip already treated lists
6780     // check if other list has any same submesh object
6781     TListOfInt& otherListOfId = *it;
6782     if ( find_first_of( theListOfId.begin(), theListOfId.end(),
6783                         otherListOfId.begin(), otherListOfId.end() ) == theListOfId.end() )
6784       continue;
6785
6786     // union two lists (from source into target)
6787     TListOfInt::iterator it2 = otherListOfId.begin();
6788     for ( ; it2 != otherListOfId.end(); it2++ ) {
6789       if ( find( theListOfId.begin(), theListOfId.end(), (*it2) ) == theListOfId.end() )
6790       {
6791         theListOfId.push_back(*it2);
6792         changed = true;
6793       }
6794     }
6795     // clear source list
6796     otherListOfId.clear();
6797   }
6798   return changed;
6799 }
6800 //-----------------------------------------------------------------------------
6801
6802 //! free memory allocated for dimension-hypothesis objects
6803 void removeDimHyps( TDimHypList* theArrOfList )
6804 {
6805   for (int i = 0; i < 4; i++ ) {
6806     TDimHypList& listOfdimHyp = theArrOfList[i];
6807     TDimHypList::const_iterator it = listOfdimHyp.begin();
6808     for ( ; it != listOfdimHyp.end(); it++ )
6809       delete (*it);
6810   }
6811 }
6812
6813 //-----------------------------------------------------------------------------
6814 /*!
6815  * \brief find common submeshes with given submesh
6816  * \param theSubMeshList list of already collected submesh to check
6817  * \param theSubMesh given submesh to intersect with other
6818  * \param theCommonSubMeshes collected common submeshes
6819  */
6820 void findCommonSubMesh (list<const SMESH_subMesh*>& theSubMeshList,
6821                         const SMESH_subMesh*        theSubMesh,
6822                         set<const SMESH_subMesh*>&  theCommon )
6823 {
6824   if ( !theSubMesh )
6825     return;
6826   list<const SMESH_subMesh*>::const_iterator it = theSubMeshList.begin();
6827   for ( ; it != theSubMeshList.end(); it++ )
6828     theSubMesh->FindIntersection( *it, theCommon );
6829   theSubMeshList.push_back( theSubMesh );
6830   //theCommon.insert( theSubMesh );
6831 }
6832
6833 //-----------------------------------------------------------------------------
6834 bool isSubMeshInList ( int smID, const TListOfListOfInt& smLists )
6835 {
6836   TListOfListOfInt::const_iterator listsIt = smLists.begin();
6837   for ( ; listsIt != smLists.end(); ++listsIt )
6838   {
6839     const TListOfInt& smIDs = *listsIt;
6840     if ( std::find( smIDs.begin(), smIDs.end(), smID ) != smIDs.end() )
6841       return true;
6842   }
6843   return false;
6844 }
6845
6846 } // namespace
6847
6848 //=============================================================================
6849 /*!
6850  * \brief Return \c true if a meshing order not yet set for a concurrent sub-mesh
6851  */
6852 //=============================================================================
6853
6854 CORBA::Boolean SMESH_Mesh_i::IsUnorderedSubMesh(CORBA::Long submeshID)
6855 {
6856   TListOfListOfInt anOrder = GetImpl().GetMeshOrder(); // already defined order
6857   if ( isSubMeshInList( submeshID, anOrder ))
6858     return false;
6859
6860   TListOfListOfInt allConurrent = findConcurrentSubMeshes();
6861   return isSubMeshInList( submeshID, allConurrent );
6862 }
6863
6864 //=============================================================================
6865 /*!
6866  * \brief Return sub-mesh objects list in meshing order
6867  */
6868 //=============================================================================
6869
6870 SMESH::submesh_array_array* SMESH_Mesh_i::GetMeshOrder()
6871 {
6872   SMESH::submesh_array_array_var aResult = new SMESH::submesh_array_array();
6873
6874   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
6875   if ( !aMeshDS )
6876     return aResult._retn();
6877
6878   TListOfListOfInt      anOrder = GetImpl().GetMeshOrder(); // already defined order
6879   TListOfListOfInt allConurrent = findConcurrentSubMeshes();
6880   anOrder.splice( anOrder.end(), allConurrent );
6881
6882   bool changed;
6883   do {
6884     changed = false;
6885     TListOfListOfInt::iterator listIt = anOrder.begin();
6886     for ( int listIndx = 1; listIt != anOrder.end(); listIt++, listIndx++ )
6887       if ( unionLists( *listIt,  anOrder, listIndx ))
6888         changed = true;
6889   }
6890   while ( changed );
6891
6892   // convert submesh ids into interface instances
6893   //  and dump command into python
6894   convertMeshOrder( anOrder, aResult, false );
6895
6896   return aResult._retn();
6897 }
6898
6899 //=============================================================================
6900 /*!
6901  * \brief Finds concurrent sub-meshes
6902  */
6903 //=============================================================================
6904
6905 TListOfListOfInt SMESH_Mesh_i::findConcurrentSubMeshes()
6906 {
6907   TListOfListOfInt anOrder;
6908   ::SMESH_Mesh& mesh = GetImpl();
6909
6910   // collect submeshes and detect concurrent algorithms and hypothesises
6911   TDimHypList dimHypListArr[4]; // dimHyp list for each shape dimension
6912
6913   map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
6914   for ( ; i_sm != _mapSubMesh.end(); i_sm++ )
6915   {
6916     ::SMESH_subMesh* sm = (*i_sm).second;
6917     // shape of submesh
6918     const TopoDS_Shape& aSubMeshShape = sm->GetSubShape();
6919
6920     // list of assigned hypothesises
6921     const list <const SMESHDS_Hypothesis*>& hypList = mesh.GetHypothesisList(aSubMeshShape);
6922     // Find out dimensions where the submesh can be concurrent.
6923     // We define the dimensions by algo of each of hypotheses in hypList
6924     list <const SMESHDS_Hypothesis*>::const_iterator hypIt = hypList.begin();
6925     for( ; hypIt != hypList.end(); hypIt++ )
6926     {
6927       SMESH_Algo* anAlgo = 0;
6928       const SMESH_Hypothesis* hyp = dynamic_cast<const SMESH_Hypothesis*>(*hypIt);
6929       if ( hyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO )
6930         // hyp it-self is algo
6931         anAlgo = (SMESH_Algo*)dynamic_cast<const SMESH_Algo*>(hyp);
6932       else {
6933         // try to find algorithm with help of sub-shapes
6934         TopExp_Explorer anExp( aSubMeshShape, shapeTypeByDim(hyp->GetDim()) );
6935         for ( ; !anAlgo && anExp.More(); anExp.Next() )
6936           anAlgo = mesh.GetGen()->GetAlgo( mesh, anExp.Current() );
6937       }
6938       if (!anAlgo)
6939         continue; // no algorithm assigned to a current submesh
6940
6941       int dim = anAlgo->GetDim(); // top concurrent dimension (see comment to SMESH_DimHyp)
6942       // the submesh can concurrent at <dim> (or lower dims if !anAlgo->NeedDiscreteBoundary()
6943       // and !anAlgo->NeedLowerHyps( dim ))
6944
6945       // create instance of dimension-hypothesis for found concurrent dimension(s) and algorithm
6946       for ( int j = anAlgo->NeedDiscreteBoundary() ? dim : 1, jn = dim; j <= jn; j++ )
6947         addDimHypInstance( j, aSubMeshShape, anAlgo, sm, hypList, dimHypListArr );
6948     }
6949   } // end iterations on submesh
6950
6951     // iterate on created dimension-hypotheses and check for concurrents
6952   for ( int i = 0; i < 4; i++ )
6953   {
6954     const TDimHypList& listOfDimHyp = dimHypListArr[i];
6955     // check for concurrents in own and other dimensions (step-by-step)
6956     TDimHypList::const_iterator dhIt = listOfDimHyp.begin();
6957     for ( ; dhIt != listOfDimHyp.end(); dhIt++ )
6958     {
6959       const SMESH_DimHyp* dimHyp = *dhIt;
6960       TDimHypList listOfConcurr;
6961       set<int>    setOfConcurrIds;
6962       // looking for concurrents and collect into own list
6963       for ( int j = i; j < 4; j++ )
6964         findConcurrents( dimHyp, dimHypListArr[j], listOfConcurr, setOfConcurrIds );
6965       // check if any concurrents found
6966       if ( listOfConcurr.size() > 0 )
6967       {
6968         // add own submesh to list of concurrent
6969         addInOrderOfPriority( dimHyp, listOfConcurr );
6970         list<int> listOfConcurrIds;
6971         TDimHypList::iterator hypIt = listOfConcurr.begin();
6972         for ( ; hypIt != listOfConcurr.end(); ++hypIt )
6973           listOfConcurrIds.push_back( (*hypIt)->_subMesh->GetId() );
6974         anOrder.push_back( listOfConcurrIds );
6975       }
6976     }
6977   }
6978
6979   removeDimHyps(dimHypListArr);
6980
6981   // now, minimize the number of concurrent groups
6982   // Here we assume that lists of submeshes can have same submesh
6983   // in case of multi-dimension algorithms, as result
6984   //  list with common submesh has to be united into one list
6985   int listIndx = 0;
6986   TListOfListOfInt::iterator listIt = anOrder.begin();
6987   for(; listIt != anOrder.end(); listIt++, listIndx++ )
6988     unionLists( *listIt,  anOrder, listIndx + 1 );
6989
6990   return anOrder;
6991 }
6992
6993 //=============================================================================
6994 /*!
6995  * \brief Set submesh object order
6996  * \param theSubMeshArray submesh array order
6997  */
6998 //=============================================================================
6999
7000 ::CORBA::Boolean SMESH_Mesh_i::SetMeshOrder(const SMESH::submesh_array_array& theSubMeshArray)
7001 {
7002   if ( _preMeshInfo )
7003     _preMeshInfo->ForgetOrLoad();
7004
7005   bool res = false;
7006   ::SMESH_Mesh& mesh = GetImpl();
7007
7008   TPythonDump aPythonDump; // prevent dump of called methods
7009   aPythonDump << "isDone = " << SMESH::SMESH_Mesh_var(_this()) << ".SetMeshOrder( [ ";
7010
7011   TListOfListOfInt subMeshOrder;
7012   for ( int i = 0, n = theSubMeshArray.length(); i < n; i++ )
7013   {
7014     const SMESH::submesh_array& aSMArray = theSubMeshArray[i];
7015     TListOfInt subMeshIds;
7016     if ( i > 0 )
7017       aPythonDump << ", ";
7018     aPythonDump << "[ ";
7019     // Collect subMeshes which should be clear
7020     //  do it list-by-list, because modification of submesh order
7021     //  take effect between concurrent submeshes only
7022     set<const SMESH_subMesh*> subMeshToClear;
7023     list<const SMESH_subMesh*> subMeshList;
7024     for ( int j = 0, jn = aSMArray.length(); j < jn; j++ )
7025     {
7026       const SMESH::SMESH_subMesh_var subMesh = SMESH::SMESH_subMesh::_duplicate(aSMArray[j]);
7027       if ( j > 0 )
7028         aPythonDump << ", ";
7029       aPythonDump << subMesh;
7030       subMeshIds.push_back( subMesh->GetId() );
7031       // detect common parts of submeshes
7032       if ( _mapSubMesh.find(subMesh->GetId()) != _mapSubMesh.end() )
7033         findCommonSubMesh( subMeshList, _mapSubMesh[ subMesh->GetId() ], subMeshToClear );
7034     }
7035     aPythonDump << " ]";
7036     subMeshOrder.push_back( subMeshIds );
7037
7038     // clear collected sub-meshes
7039     set<const SMESH_subMesh*>::iterator clrIt = subMeshToClear.begin();
7040     for ( ; clrIt != subMeshToClear.end(); clrIt++ )
7041       if ( SMESH_subMesh* sm = (SMESH_subMesh*)*clrIt )
7042       {
7043         sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
7044         if ( SMESH_Algo* algo = sm->GetAlgo() ) // #16748
7045           sm->AlgoStateEngine( SMESH_subMesh::MODIF_HYP, algo ); // to clear a cached algo
7046       }
7047   }
7048   aPythonDump << " ])";
7049
7050   mesh.SetMeshOrder( subMeshOrder );
7051   res = true;
7052
7053   SMESH::SMESH_Mesh_var me = _this();
7054   _gen_i->UpdateIcons( me );
7055
7056   return res;
7057 }
7058
7059 //=============================================================================
7060 /*!
7061  * \brief Convert submesh ids into submesh interfaces
7062  */
7063 //=============================================================================
7064
7065 void SMESH_Mesh_i::convertMeshOrder (const TListOfListOfInt&     theIdsOrder,
7066                                      SMESH::submesh_array_array& theResOrder,
7067                                      const bool                  theIsDump)
7068 {
7069   int nbSet = theIdsOrder.size();
7070   TPythonDump aPythonDump; // prevent dump of called methods
7071   if ( theIsDump )
7072     aPythonDump << "[ ";
7073   theResOrder.length(nbSet);
7074   TListOfListOfInt::const_iterator it = theIdsOrder.begin();
7075   int listIndx = 0;
7076   for( ; it != theIdsOrder.end(); it++ )
7077   {
7078     // translate submesh identificators into submesh objects
7079     //  takeing into account real number of concurrent lists
7080     const TListOfInt& aSubOrder = (*it);
7081     if (!aSubOrder.size())
7082       continue;
7083     if ( theIsDump )
7084       aPythonDump << "[ ";
7085     // convert shape indices into interfaces
7086     SMESH::submesh_array_var aResSubSet = new SMESH::submesh_array();
7087     aResSubSet->length(aSubOrder.size());
7088     TListOfInt::const_iterator subIt = aSubOrder.begin();
7089     int j;
7090     for( j = 0; subIt != aSubOrder.end(); subIt++ )
7091     {
7092       if ( _mapSubMeshIor.find(*subIt) == _mapSubMeshIor.end() )
7093         continue;
7094       SMESH::SMESH_subMesh_var subMesh =
7095         SMESH::SMESH_subMesh::_duplicate( _mapSubMeshIor[*subIt] );
7096       if ( theIsDump ) {
7097         if ( j > 0 )
7098           aPythonDump << ", ";
7099         aPythonDump << subMesh;
7100       }
7101       aResSubSet[ j++ ] = subMesh;
7102     }
7103     if ( theIsDump )
7104       aPythonDump << " ]";
7105     if ( j > 1 )
7106       theResOrder[ listIndx++ ] = aResSubSet;
7107   }
7108   // correct number of lists
7109   theResOrder.length( listIndx );
7110
7111   if ( theIsDump ) {
7112     // finilise python dump
7113     aPythonDump << " ]";
7114     aPythonDump << " = " << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshOrder()";
7115   }
7116 }
7117
7118 namespace // utils used by SMESH_MeshPartDS
7119 {
7120   /*!
7121    * \brief Class used to access to protected data of SMDS_MeshInfo
7122    */
7123   struct TMeshInfo : public SMDS_MeshInfo
7124   {
7125     void Add(const SMDS_MeshElement* e) { SMDS_MeshInfo::addWithPoly( e ); }
7126   };
7127   /*!
7128    * \brief Element holing its ID only
7129    */
7130   struct TElemID : public SMDS_LinearEdge
7131   {
7132     TElemID(int ID) : SMDS_LinearEdge(0,0) { setID( ID ); }
7133   };
7134 }
7135
7136 //================================================================================
7137 //
7138 // Implementation of SMESH_MeshPartDS
7139 //
7140 SMESH_MeshPartDS::SMESH_MeshPartDS(SMESH::SMESH_IDSource_ptr meshPart):
7141   SMESHDS_Mesh( /*meshID=*/-1, /*isEmbeddedMode=*/true)
7142 {
7143   SMESH::SMESH_Mesh_var mesh = meshPart->GetMesh();
7144   SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
7145
7146   mesh_i->Load();
7147   _meshDS = mesh_i->GetImpl().GetMeshDS();
7148
7149   SetPersistentId( _meshDS->GetPersistentId() );
7150
7151   if ( mesh_i == SMESH::DownCast<SMESH_Mesh_i*>( meshPart ))
7152   {
7153     // <meshPart> is the whole mesh
7154     myInfo = _meshDS->GetMeshInfo(); // copy mesh info;
7155     // copy groups
7156     set<SMESHDS_GroupBase*>& myGroupSet = const_cast<set<SMESHDS_GroupBase*>&>( GetGroups() );
7157     myGroupSet = _meshDS->GetGroups();
7158   }
7159   else
7160   {
7161     TMeshInfo tmpInfo;
7162     SMESH::smIdType_array_var       anIDs = meshPart->GetIDs();
7163     SMESH::array_of_ElementType_var types = meshPart->GetTypes();
7164     if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
7165     {
7166       for ( CORBA::ULong i=0; i < anIDs->length(); i++ )
7167         if ( const SMDS_MeshNode * n = _meshDS->FindNode( anIDs[i] ))
7168           if ( _elements[ SMDSAbs_Node ].insert( n ).second )
7169             tmpInfo.Add( n );
7170     }
7171     else
7172     {
7173       for ( CORBA::ULong i=0; i < anIDs->length(); i++ )
7174         if ( const SMDS_MeshElement * e = _meshDS->FindElement(anIDs[i]))
7175           if ( _elements[ e->GetType() ].insert( e ).second )
7176           {
7177             tmpInfo.Add( e );
7178             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7179             while ( nIt->more() )
7180             {
7181               const SMDS_MeshNode * n = (const SMDS_MeshNode*) nIt->next();
7182               if ( _elements[ SMDSAbs_Node ].insert( n ).second )
7183                 tmpInfo.Add( n );
7184             }
7185           }
7186     }
7187     myInfo = tmpInfo;
7188
7189     ShapeToMesh( _meshDS->ShapeToMesh() );
7190
7191     _meshDS = 0; // to enforce iteration on _elements and _nodes
7192   }
7193 }
7194 // -------------------------------------------------------------------------------------
7195 SMESH_MeshPartDS::SMESH_MeshPartDS(const std::list< const SMDS_MeshElement* > & meshPart):
7196   SMESHDS_Mesh( /*meshID=*/-1, /*isEmbeddedMode=*/true), _meshDS(0)
7197 {
7198   TMeshInfo tmpInfo;
7199   list< const SMDS_MeshElement* >::const_iterator partIt = meshPart.begin();
7200   for ( ; partIt != meshPart.end(); ++partIt )
7201     if ( const SMDS_MeshElement * e = *partIt )
7202       if ( _elements[ e->GetType() ].insert( e ).second )
7203       {
7204         tmpInfo.Add( e );
7205         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7206         while ( nIt->more() )
7207         {
7208           const SMDS_MeshNode * n = (const SMDS_MeshNode*) nIt->next();
7209           if ( _elements[ SMDSAbs_Node ].insert( n ).second )
7210             tmpInfo.Add( n );
7211         }
7212       }
7213   myInfo = tmpInfo;
7214 }
7215 // -------------------------------------------------------------------------------------
7216 const SMDS_MeshElement * SMESH_MeshPartDS::FindElement(int IDelem) const
7217 {
7218   if ( _meshDS ) return _meshDS->FindElement( IDelem );
7219
7220   TElemID elem( IDelem );
7221   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
7222     if ( !_elements[ iType ].empty() )
7223     {
7224       TIDSortedElemSet::const_iterator it = _elements[ iType ].find( &elem );
7225       if ( it != _elements[ iType ].end() )
7226         return *it;
7227     }
7228   return 0;
7229 }
7230 // -------------------------------------------------------------------------------------
7231 bool SMESH_MeshPartDS::HasNumerationHoles()
7232 {
7233   if ( _meshDS ) return _meshDS->HasNumerationHoles();
7234
7235   return ( MinNodeID() != 1 ||
7236            MaxNodeID() != NbNodes() ||
7237            MinElementID() != 1 ||
7238            MaxElementID() != NbElements() );
7239 }
7240 // -------------------------------------------------------------------------------------
7241 smIdType SMESH_MeshPartDS::MaxNodeID() const
7242 {
7243   if ( _meshDS ) return _meshDS->MaxNodeID();
7244   return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].rbegin())->GetID();
7245 }
7246 // -------------------------------------------------------------------------------------
7247 smIdType SMESH_MeshPartDS::MinNodeID() const
7248 {
7249   if ( _meshDS ) return _meshDS->MinNodeID();
7250   return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].begin())->GetID();
7251 }  
7252 // -------------------------------------------------------------------------------------
7253 smIdType SMESH_MeshPartDS::MaxElementID() const
7254 {
7255   if ( _meshDS ) return _meshDS->MaxElementID();
7256   smIdType maxID = 0;
7257   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
7258     if ( !_elements[ iType ].empty() )
7259       maxID = std::max( maxID, (*_elements[ iType ].rbegin())->GetID() );
7260   return maxID;
7261 }
7262 // -------------------------------------------------------------------------------------
7263 smIdType SMESH_MeshPartDS::MinElementID() const
7264 {
7265   if ( _meshDS ) return _meshDS->MinElementID();
7266   smIdType minID = 0;
7267   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
7268     if ( !_elements[ iType ].empty() )
7269       minID = std::min( minID, (*_elements[ iType ].begin())->GetID() );
7270   return minID;
7271 }
7272 // -------------------------------------------------------------------------------------
7273 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementGeomIterator(SMDSAbs_GeometryType geomType) const
7274 {
7275   if ( _meshDS ) return _meshDS->elementGeomIterator( geomType );
7276
7277   typedef SMDS_SetIterator
7278     <const SMDS_MeshElement*,
7279     TIDSortedElemSet::const_iterator,
7280     SMDS::SimpleAccessor<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator>,
7281     SMDS_MeshElement::GeomFilter
7282     > TIter;
7283
7284   SMDSAbs_ElementType type = SMDS_MeshCell::ElemType( geomType );
7285
7286   return SMDS_ElemIteratorPtr( new TIter( _elements[type].begin(),
7287                                           _elements[type].end(),
7288                                           SMDS_MeshElement::GeomFilter( geomType )));
7289 }
7290 // -------------------------------------------------------------------------------------
7291 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementEntityIterator(SMDSAbs_EntityType entity) const
7292 {
7293   if ( _meshDS ) return _meshDS->elementEntityIterator( entity );
7294
7295   typedef SMDS_SetIterator
7296     <const SMDS_MeshElement*,
7297     TIDSortedElemSet::const_iterator,
7298     SMDS::SimpleAccessor<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator>,
7299     SMDS_MeshElement::EntityFilter
7300     > TIter;
7301
7302   SMDSAbs_ElementType type = SMDS_MeshCell::ElemType( entity );
7303
7304   return SMDS_ElemIteratorPtr( new TIter( _elements[type].begin(),
7305                                           _elements[type].end(),
7306                                           SMDS_MeshElement::EntityFilter( entity )));
7307 }
7308 // -------------------------------------------------------------------------------------
7309 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementsIterator(SMDSAbs_ElementType type) const
7310 {
7311   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
7312   if ( type == SMDSAbs_All && !_meshDS )
7313   {
7314     typedef vector< SMDS_ElemIteratorPtr > TIterVec;
7315     TIterVec iterVec;
7316     for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
7317       if ( !_elements[i].empty() && i != SMDSAbs_Node )
7318         iterVec.push_back
7319           ( SMDS_ElemIteratorPtr( new TIter( _elements[i].begin(), _elements[i].end() )));
7320
7321     typedef SMDS_IteratorOnIterators<const SMDS_MeshElement*, TIterVec > TIterOnIters;
7322     return SMDS_ElemIteratorPtr( new TIterOnIters( iterVec ));
7323   }
7324   return _meshDS ? _meshDS->elementsIterator(type) : SMDS_ElemIteratorPtr
7325       ( new TIter( _elements[type].begin(), _elements[type].end() ));
7326 }
7327 // -------------------------------------------------------------------------------------
7328 #define _GET_ITER_DEFINE( iterType, methName, elem, elemType)                       \
7329   iterType SMESH_MeshPartDS::methName() const                 \
7330   {                                                                                 \
7331     typedef SMDS_SetIterator<const elem*, TIDSortedElemSet::const_iterator > TIter; \
7332     return _meshDS ? _meshDS->methName() : iterType                 \
7333       ( new TIter( _elements[elemType].begin(), _elements[elemType].end() ));       \
7334   }
7335 // -------------------------------------------------------------------------------------
7336 _GET_ITER_DEFINE( SMDS_NodeIteratorPtr, nodesIterator, SMDS_MeshNode, SMDSAbs_Node )
7337 _GET_ITER_DEFINE( SMDS_EdgeIteratorPtr, edgesIterator, SMDS_MeshEdge, SMDSAbs_Edge )
7338 _GET_ITER_DEFINE( SMDS_FaceIteratorPtr, facesIterator, SMDS_MeshFace, SMDSAbs_Face )
7339 _GET_ITER_DEFINE( SMDS_VolumeIteratorPtr, volumesIterator, SMDS_MeshVolume, SMDSAbs_Volume)
7340 #undef _GET_ITER_DEFINE
7341 //
7342 // END Implementation of SMESH_MeshPartDS
7343 //
7344 //================================================================================