Salome HOME
022501: [CEA 1076] Impossible to mesh at its position a translated without copy shape...
[modules/smesh.git] / src / SMESH_I / SMESH_Mesh_i.cxx
1 // Copyright (C) 2007-2014  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_EdgePosition.hxx"
33 #include "SMDS_ElemIterator.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_IteratorOnIterators.hxx"
36 #include "SMDS_MeshGroup.hxx"
37 #include "SMDS_SetIterator.hxx"
38 #include "SMDS_VolumeTool.hxx"
39 #include "SMESHDS_Command.hxx"
40 #include "SMESHDS_CommandType.hxx"
41 #include "SMESHDS_Group.hxx"
42 #include "SMESHDS_GroupOnGeom.hxx"
43 #include "SMESH_Controls.hxx"
44 #include "SMESH_Filter_i.hxx"
45 #include "SMESH_Gen_i.hxx"
46 #include "SMESH_Group.hxx"
47 #include "SMESH_Group_i.hxx"
48 #include "SMESH_MeshAlgos.hxx"
49 #include "SMESH_MeshEditor.hxx"
50 #include "SMESH_MeshEditor_i.hxx"
51 #include "SMESH_MeshPartDS.hxx"
52 #include "SMESH_MesherHelper.hxx"
53 #include "SMESH_PreMeshInfo.hxx"
54 #include "SMESH_PythonDump.hxx"
55 #include "SMESH_subMesh_i.hxx"
56
57 #include <OpUtil.hxx>
58 #include <SALOMEDS_Attributes_wrap.hxx>
59 #include <SALOMEDS_wrap.hxx>
60 #include <SALOME_NamingService.hxx>
61 #include <Utils_ExceptHandlers.hxx>
62 #include <Utils_SINGLETON.hxx>
63 #include <utilities.h>
64
65 #include <GEOMImpl_Types.hxx>
66 #include <GEOM_wrap.hxx>
67
68 // OCCT Includes
69 #include <BRep_Builder.hxx>
70 #include <OSD_Directory.hxx>
71 #include <OSD_File.hxx>
72 #include <OSD_Path.hxx>
73 #include <OSD_Protection.hxx>
74 #include <Standard_OutOfMemory.hxx>
75 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
76 #include <TColStd_MapOfInteger.hxx>
77 #include <TColStd_SequenceOfInteger.hxx>
78 #include <TCollection_AsciiString.hxx>
79 #include <TopExp.hxx>
80 #include <TopExp_Explorer.hxx>
81 #include <TopTools_MapIteratorOfMapOfShape.hxx>
82 #include <TopTools_MapOfShape.hxx>
83 #include <TopoDS_Compound.hxx>
84
85 // STL Includes
86 #include <algorithm>
87 #include <string>
88 #include <iostream>
89 #include <sstream>
90
91 #include <sys/stat.h>
92
93 // to pass CORBA exception through SMESH_TRY
94 #define SMY_OWN_CATCH catch( SALOME::SALOME_Exception& se ) { throw se; }
95
96 #include "SMESH_TryCatch.hxx" // include after OCCT headers!
97
98 #ifdef _DEBUG_
99 static int MYDEBUG = 0;
100 #else
101 static int MYDEBUG = 0;
102 #endif
103
104 using namespace std;
105 using SMESH::TPythonDump;
106
107 int SMESH_Mesh_i::_idGenerator = 0;
108
109 //=============================================================================
110 /*!
111  *  Constructor
112  */
113 //=============================================================================
114
115 SMESH_Mesh_i::SMESH_Mesh_i( PortableServer::POA_ptr thePOA,
116                             SMESH_Gen_i*            gen_i,
117                             CORBA::Long studyId )
118 : SALOME::GenericObj_i( thePOA )
119 {
120   MESSAGE("SMESH_Mesh_i");
121   _impl          = NULL;
122   _gen_i         = gen_i;
123   _id            = _idGenerator++;
124   _studyId       = studyId;
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   MESSAGE("~SMESH_Mesh_i");
140
141   // destroy groups
142   map<int, SMESH::SMESH_GroupBase_ptr>::iterator itGr;
143   for (itGr = _mapGroups.begin(); itGr != _mapGroups.end(); itGr++)
144     if (SMESH_GroupBase_i* aGroup = SMESH::DownCast<SMESH_GroupBase_i*>(itGr->second))
145     {
146       aGroup->UnRegister();
147       SMESH::SMESH_GroupBase_var( itGr->second );
148     }
149   _mapGroups.clear();
150
151   // destroy submeshes
152   map<int, SMESH::SMESH_subMesh_ptr>::iterator itSM;
153   for ( itSM = _mapSubMeshIor.begin(); itSM != _mapSubMeshIor.end(); itSM++ )
154     if ( SMESH_subMesh_i* aSubMesh = SMESH::DownCast<SMESH_subMesh_i*>( itSM->second ))
155     {
156       aSubMesh->UnRegister();
157       SMESH::SMESH_subMesh_var( itSM->second );
158     }
159   _mapSubMeshIor.clear();
160
161   // destroy hypotheses. _mapHypo contains all hyps ever been assigned
162   map<int, SMESH::SMESH_Hypothesis_ptr>::iterator itH;
163   for ( itH = _mapHypo.begin(); itH != _mapHypo.end(); itH++ ) {
164     if ( SMESH_Hypothesis_i* hyp_i = SMESH::DownCast<SMESH_Hypothesis_i*>( itH->second ))
165       if ( SMESH_Hypothesis * smHyp = _impl->GetHypothesis( itH->first ))
166         if ( _impl->GetMeshDS()->IsUsedHypothesis( smHyp ))
167           hyp_i->UnRegister();
168
169     SMESH::SMESH_Hypothesis_var( itH->second ); // decref CORBA object
170   }
171   _mapHypo.clear();
172
173   delete _editor; _editor = NULL;
174   delete _previewEditor; _previewEditor = NULL;
175   delete _impl; _impl = NULL;
176   delete _preMeshInfo; _preMeshInfo = NULL;
177 }
178
179 //=============================================================================
180 /*!
181  *  SetShape
182  *
183  *  Associates <this> mesh with <theShape> and puts a reference
184  *  to <theShape> into the current study;
185  *  the previous shape is substituted by the new one.
186  */
187 //=============================================================================
188
189 void SMESH_Mesh_i::SetShape( GEOM::GEOM_Object_ptr theShapeObject )
190     throw (SALOME::SALOME_Exception)
191 {
192   Unexpect aCatch(SALOME_SalomeException);
193   try {
194     _impl->ShapeToMesh( _gen_i->GeomObjectToShape( theShapeObject ));
195   }
196   catch(SALOME_Exception & S_ex) {
197     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
198   }
199   // to track changes of GEOM groups
200   SMESH::SMESH_Mesh_var mesh = _this();
201   addGeomGroupData( theShapeObject, mesh );
202   _mainShapeTick = theShapeObject->GetTick();
203 }
204
205 //================================================================================
206 /*!
207  * \brief return true if mesh has a shape to build a shape on
208  */
209 //================================================================================
210
211 CORBA::Boolean SMESH_Mesh_i::HasShapeToMesh()
212   throw (SALOME::SALOME_Exception)
213 {
214   Unexpect aCatch(SALOME_SalomeException);
215   bool res = false;
216   try {
217     res = _impl->HasShapeToMesh();
218   }
219   catch(SALOME_Exception & S_ex) {
220     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
221   }
222   return res;
223 }
224
225 //=======================================================================
226 //function : GetShapeToMesh
227 //purpose  :
228 //=======================================================================
229
230 GEOM::GEOM_Object_ptr SMESH_Mesh_i::GetShapeToMesh()
231   throw (SALOME::SALOME_Exception)
232 {
233   Unexpect aCatch(SALOME_SalomeException);
234   GEOM::GEOM_Object_var aShapeObj;
235   try {
236     TopoDS_Shape S = _impl->GetMeshDS()->ShapeToMesh();
237     if ( !S.IsNull() )
238       aShapeObj = _gen_i->ShapeToGeomObject( S );
239   }
240   catch(SALOME_Exception & S_ex) {
241     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
242   }
243   return aShapeObj._retn();
244 }
245
246 //================================================================================
247 /*!
248  * \brief Return false if the mesh is not yet fully loaded from the study file
249  */
250 //================================================================================
251
252 CORBA::Boolean SMESH_Mesh_i::IsLoaded() throw (SALOME::SALOME_Exception)
253 {
254   Unexpect aCatch(SALOME_SalomeException);
255   return !_preMeshInfo;
256 }
257
258 //================================================================================
259 /*!
260  * \brief Load full mesh data from the study file
261  */
262 //================================================================================
263
264 void SMESH_Mesh_i::Load() throw (SALOME::SALOME_Exception)
265 {
266   Unexpect aCatch(SALOME_SalomeException);
267   if ( _preMeshInfo )
268     _preMeshInfo->FullLoadFromFile();
269 }
270
271 //================================================================================
272 /*!
273  * \brief Remove all nodes and elements
274  */
275 //================================================================================
276
277 void SMESH_Mesh_i::Clear() throw (SALOME::SALOME_Exception)
278 {
279   Unexpect aCatch(SALOME_SalomeException);
280   if ( _preMeshInfo )
281     _preMeshInfo->ForgetAllData();
282
283   try {
284     _impl->Clear();
285     //CheckGeomGroupModif(); // issue 20145
286   }
287   catch(SALOME_Exception & S_ex) {
288     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
289   }
290   _impl->GetMeshDS()->Modified();
291
292   TPythonDump() <<  SMESH::SMESH_Mesh_var(_this()) << ".Clear()";
293 }
294
295 //================================================================================
296 /*!
297  * \brief Remove all nodes and elements for indicated shape
298  */
299 //================================================================================
300
301 void SMESH_Mesh_i::ClearSubMesh(CORBA::Long ShapeID)
302   throw (SALOME::SALOME_Exception)
303 {
304   Unexpect aCatch(SALOME_SalomeException);
305   if ( _preMeshInfo )
306     _preMeshInfo->FullLoadFromFile();
307
308   try {
309     _impl->ClearSubMesh( ShapeID );
310   }
311   catch(SALOME_Exception & S_ex) {
312     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
313   }
314   _impl->GetMeshDS()->Modified();
315
316   TPythonDump() <<  SMESH::SMESH_Mesh_var(_this()) << ".ClearSubMesh( " << ShapeID << " )";
317 }
318
319 //=============================================================================
320 /*!
321  * Convert enum Driver_Mesh::Status to SMESH::DriverMED_ReadStatus
322  */
323 //=============================================================================
324
325 static SMESH::DriverMED_ReadStatus ConvertDriverMEDReadStatus (int theStatus)
326 {
327   SMESH::DriverMED_ReadStatus res;
328   switch (theStatus)
329   {
330   case DriverMED_R_SMESHDS_Mesh::DRS_OK:
331     res = SMESH::DRS_OK; break;
332   case DriverMED_R_SMESHDS_Mesh::DRS_EMPTY:
333     res = SMESH::DRS_EMPTY; break;
334   case DriverMED_R_SMESHDS_Mesh::DRS_WARN_RENUMBER:
335     res = SMESH::DRS_WARN_RENUMBER; break;
336   case DriverMED_R_SMESHDS_Mesh::DRS_WARN_SKIP_ELEM:
337     res = SMESH::DRS_WARN_SKIP_ELEM; break;
338   case DriverMED_R_SMESHDS_Mesh::DRS_WARN_DESCENDING:
339     res = SMESH::DRS_WARN_DESCENDING; break;
340   case DriverMED_R_SMESHDS_Mesh::DRS_FAIL:
341   default:
342     res = SMESH::DRS_FAIL; break;
343   }
344   return res;
345 }
346
347 //=============================================================================
348 /*!
349  * Convert ::SMESH_ComputeError to SMESH::ComputeError
350  */
351 //=============================================================================
352
353 static SMESH::ComputeError* ConvertComputeError( SMESH_ComputeErrorPtr errorPtr )
354 {
355   SMESH::ComputeError_var errVar = new SMESH::ComputeError();
356   errVar->subShapeID = -1;
357   errVar->hasBadMesh = false;
358
359   if ( !errorPtr || errorPtr->IsOK() )
360   {
361     errVar->code = SMESH::COMPERR_OK;
362   }
363   else
364   {
365     errVar->code    = ConvertDriverMEDReadStatus( errorPtr->myName );
366     errVar->comment = errorPtr->myComment.c_str();
367   }
368   return errVar._retn();
369 }
370
371 //=============================================================================
372 /*!
373  *  ImportMEDFile
374  *
375  *  Imports mesh data from MED file
376  */
377 //=============================================================================
378
379 SMESH::DriverMED_ReadStatus
380 SMESH_Mesh_i::ImportMEDFile( const char* theFileName, const char* theMeshName )
381   throw ( SALOME::SALOME_Exception )
382 {
383   Unexpect aCatch(SALOME_SalomeException);
384   int status;
385   try {
386     status = _impl->MEDToMesh( theFileName, theMeshName );
387   }
388   catch( SALOME_Exception& S_ex ) {
389     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
390   }
391   catch ( ... ) {
392     THROW_SALOME_CORBA_EXCEPTION("ImportMEDFile(): unknown exception", SALOME::BAD_PARAM);
393   }
394
395   CreateGroupServants();
396
397   int major, minor, release;
398   if( !MED::getMEDVersion( theFileName, major, minor, release ) )
399     major = minor = release = -1;
400   _medFileInfo           = new SMESH::MedFileInfo();
401   _medFileInfo->fileName = theFileName;
402   _medFileInfo->fileSize = 0;
403   _medFileInfo->major    = major;
404   _medFileInfo->minor    = minor;
405   _medFileInfo->release  = release;
406 #ifdef WIN32
407   struct _stati64 d;
408   if ( ::_stati64( theFileName, &d ) != -1 )
409 #else
410   struct stat64 d;
411   if ( ::stat64( theFileName, &d ) != -1 )
412 #endif
413     _medFileInfo->fileSize = d.st_size;
414
415   return ConvertDriverMEDReadStatus(status);
416 }
417
418 //================================================================================
419 /*!
420  * \brief Imports mesh data from the CGNS file
421  */
422 //================================================================================
423
424 SMESH::DriverMED_ReadStatus SMESH_Mesh_i::ImportCGNSFile( const char*  theFileName,
425                                                           const int    theMeshIndex,
426                                                           std::string& theMeshName )
427   throw ( SALOME::SALOME_Exception )
428 {
429   Unexpect aCatch(SALOME_SalomeException);
430   int status;
431   try {
432     status = _impl->CGNSToMesh( theFileName, theMeshIndex, theMeshName );
433   }
434   catch( SALOME_Exception& S_ex ) {
435     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
436   }
437   catch ( ... ) {
438     THROW_SALOME_CORBA_EXCEPTION("ImportCGNSFile(): unknown exception", SALOME::BAD_PARAM);
439   }
440
441   CreateGroupServants();
442
443   return ConvertDriverMEDReadStatus(status);
444 }
445
446 //================================================================================
447 /*!
448  * \brief Return string representation of a MED file version comprising nbDigits
449  */
450 //================================================================================
451
452 char* SMESH_Mesh_i::GetVersionString(SMESH::MED_VERSION version, CORBA::Short nbDigits)
453 {
454   string ver = DriverMED_W_SMESHDS_Mesh::GetVersionString(MED::EVersion(version),
455                                                           nbDigits);
456   return CORBA::string_dup( ver.c_str() );
457 }
458
459 //=============================================================================
460 /*!
461  *  ImportUNVFile
462  *
463  *  Imports mesh data from MED file
464  */
465 //=============================================================================
466
467 int SMESH_Mesh_i::ImportUNVFile( const char* theFileName )
468   throw ( SALOME::SALOME_Exception )
469 {
470   SMESH_TRY;
471
472   // Read mesh with name = <theMeshName> into SMESH_Mesh
473   _impl->UNVToMesh( theFileName );
474
475   CreateGroupServants();
476
477   SMESH_CATCH( SMESH::throwCorbaException );
478
479   return 1;
480 }
481
482 //=============================================================================
483 /*!
484  *  ImportSTLFile
485  *
486  *  Imports mesh data from STL file
487  */
488 //=============================================================================
489 int SMESH_Mesh_i::ImportSTLFile( const char* theFileName )
490   throw ( SALOME::SALOME_Exception )
491 {
492   SMESH_TRY;
493
494   // Read mesh with name = <theMeshName> into SMESH_Mesh
495   _impl->STLToMesh( theFileName );
496
497   SMESH_CATCH( SMESH::throwCorbaException );
498
499   return 1;
500 }
501
502 //================================================================================
503 /*!
504  * \brief Function used in SMESH_CATCH by ImportGMFFile()
505  */
506 //================================================================================
507
508 namespace
509 {
510   SMESH_ComputeErrorPtr exceptionToComputeError(const char* excText)
511   {
512     return SMESH_ComputeError::New( Driver_Mesh::DRS_FAIL, excText );
513   }
514 }
515
516 //================================================================================
517 /*!
518  * \brief Imports data from a GMF file and returns an error description
519  */
520 //================================================================================
521
522 SMESH::ComputeError* SMESH_Mesh_i::ImportGMFFile( const char* theFileName,
523                                                   bool        theMakeRequiredGroups )
524   throw (SALOME::SALOME_Exception)
525 {
526   SMESH_ComputeErrorPtr error;
527
528 #undef SMESH_CAUGHT
529 #define SMESH_CAUGHT error =
530   SMESH_TRY;
531
532   error = _impl->GMFToMesh( theFileName, theMakeRequiredGroups );
533
534   SMESH_CATCH( exceptionToComputeError );
535 #undef SMESH_CAUGHT
536 #define SMESH_CAUGHT
537
538   CreateGroupServants();
539
540   return ConvertComputeError( error );
541 }
542
543 //=============================================================================
544 /*!
545  *
546  */
547 //=============================================================================
548
549 #define RETURNCASE(hyp_stat) case SMESH_Hypothesis::hyp_stat: return SMESH::hyp_stat;
550
551 SMESH::Hypothesis_Status SMESH_Mesh_i::ConvertHypothesisStatus
552                          (SMESH_Hypothesis::Hypothesis_Status theStatus)
553 {
554   switch (theStatus) {
555   RETURNCASE( HYP_OK            );
556   RETURNCASE( HYP_MISSING       );
557   RETURNCASE( HYP_CONCURENT     );
558   RETURNCASE( HYP_BAD_PARAMETER );
559   RETURNCASE( HYP_HIDDEN_ALGO   );
560   RETURNCASE( HYP_HIDING_ALGO   );
561   RETURNCASE( HYP_UNKNOWN_FATAL );
562   RETURNCASE( HYP_INCOMPATIBLE  );
563   RETURNCASE( HYP_NOTCONFORM    );
564   RETURNCASE( HYP_ALREADY_EXIST );
565   RETURNCASE( HYP_BAD_DIM       );
566   RETURNCASE( HYP_BAD_SUBSHAPE  );
567   RETURNCASE( HYP_BAD_GEOMETRY  );
568   RETURNCASE( HYP_NEED_SHAPE    );
569   default:;
570   }
571   return SMESH::HYP_UNKNOWN_FATAL;
572 }
573
574 //=============================================================================
575 /*!
576  *  AddHypothesis
577  *
578  *  calls internal addHypothesis() and then adds a reference to <anHyp> under
579  *  the SObject actually having a reference to <aSubShape>.
580  *  NB: For this method to work, it is necessary to add a reference to sub-shape first.
581  */
582 //=============================================================================
583
584 SMESH::Hypothesis_Status SMESH_Mesh_i::AddHypothesis(GEOM::GEOM_Object_ptr       aSubShapeObject,
585                                                      SMESH::SMESH_Hypothesis_ptr anHyp)
586   throw(SALOME::SALOME_Exception)
587 {
588   Unexpect aCatch(SALOME_SalomeException);
589   if ( _preMeshInfo )
590     _preMeshInfo->ForgetOrLoad();
591
592   SMESH_Hypothesis::Hypothesis_Status status = addHypothesis( aSubShapeObject, anHyp );
593
594   SMESH::SMESH_Mesh_var mesh( _this() );
595   if ( !SMESH_Hypothesis::IsStatusFatal(status) )
596   {
597     SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
598     _gen_i->AddHypothesisToShape( study, mesh, aSubShapeObject, anHyp );
599   }
600   if(MYDEBUG) MESSAGE( " AddHypothesis(): status = " << status );
601
602   // Update Python script
603   //if(_impl->HasShapeToMesh())
604   {
605     TPythonDump() << "status = " << mesh << ".AddHypothesis( "
606                   << aSubShapeObject << ", " << anHyp << " )";
607   }
608   // else {
609   //   TPythonDump() << "status = " << mesh << ".AddHypothesis( "<< anHyp << " )";
610   // }
611
612   return ConvertHypothesisStatus(status);
613 }
614
615 //=============================================================================
616 /*!
617  *
618  */
619 //=============================================================================
620
621 SMESH_Hypothesis::Hypothesis_Status
622 SMESH_Mesh_i::addHypothesis(GEOM::GEOM_Object_ptr       aSubShapeObject,
623                             SMESH::SMESH_Hypothesis_ptr anHyp)
624 {
625   if(MYDEBUG) MESSAGE("addHypothesis");
626
627   if (CORBA::is_nil( aSubShapeObject ) && HasShapeToMesh())
628     THROW_SALOME_CORBA_EXCEPTION("bad Sub-shape reference",SALOME::BAD_PARAM);
629
630   if (CORBA::is_nil( anHyp ))
631     THROW_SALOME_CORBA_EXCEPTION("bad hypothesis reference",SALOME::BAD_PARAM);
632
633   SMESH_Hypothesis::Hypothesis_Status status = SMESH_Hypothesis::HYP_OK;
634   try
635   {
636     TopoDS_Shape myLocSubShape;
637     //use PseudoShape in case if mesh has no shape
638     if(HasShapeToMesh())
639       myLocSubShape = _gen_i->GeomObjectToShape( aSubShapeObject);
640     else              
641       myLocSubShape = _impl->GetShapeToMesh();
642     
643     const int hypId = anHyp->GetId();
644     status = _impl->AddHypothesis(myLocSubShape, hypId);
645     if ( !SMESH_Hypothesis::IsStatusFatal(status) ) {
646       _mapHypo[hypId] = SMESH::SMESH_Hypothesis::_duplicate( anHyp );
647       anHyp->Register();
648       // assure there is a corresponding submesh
649       if ( !_impl->IsMainShape( myLocSubShape )) {
650         int shapeId = _impl->GetMeshDS()->ShapeToIndex( myLocSubShape );
651         if ( _mapSubMesh_i.find( shapeId ) == _mapSubMesh_i.end() )
652           SMESH::SMESH_subMesh_var( createSubMesh( aSubShapeObject ));
653       }
654     }
655   }
656   catch(SALOME_Exception & S_ex)
657   {
658     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
659   }
660   return status;
661 }
662
663 //=============================================================================
664 /*!
665  *
666  */
667 //=============================================================================
668
669 SMESH::Hypothesis_Status SMESH_Mesh_i::RemoveHypothesis(GEOM::GEOM_Object_ptr aSubShapeObject,
670                                                         SMESH::SMESH_Hypothesis_ptr anHyp)
671   throw(SALOME::SALOME_Exception)
672 {
673   Unexpect aCatch(SALOME_SalomeException);
674   if ( _preMeshInfo )
675     _preMeshInfo->ForgetOrLoad();
676
677   SMESH_Hypothesis::Hypothesis_Status status = removeHypothesis( aSubShapeObject, anHyp );
678   SMESH::SMESH_Mesh_var mesh = _this();
679
680   if ( !SMESH_Hypothesis::IsStatusFatal(status) )
681   {
682     SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
683     _gen_i->RemoveHypothesisFromShape( study, mesh, aSubShapeObject, anHyp );
684   }
685   // Update Python script
686   if(_impl->HasShapeToMesh())
687     TPythonDump() << "status = " << mesh << ".RemoveHypothesis( "
688                   << aSubShapeObject << ", " << anHyp << " )";
689   else
690     TPythonDump() << "status = " << mesh << ".RemoveHypothesis( "
691                   << anHyp << " )";
692
693   return ConvertHypothesisStatus(status);
694 }
695
696 //=============================================================================
697 /*!
698  *
699  */
700 //=============================================================================
701
702 SMESH_Hypothesis::Hypothesis_Status
703 SMESH_Mesh_i::removeHypothesis(GEOM::GEOM_Object_ptr       aSubShapeObject,
704                                SMESH::SMESH_Hypothesis_ptr anHyp)
705 {
706   if(MYDEBUG) MESSAGE("removeHypothesis()");
707
708   if (CORBA::is_nil( aSubShapeObject ) && HasShapeToMesh())
709     THROW_SALOME_CORBA_EXCEPTION("bad Sub-shape reference", SALOME::BAD_PARAM);
710
711   if (CORBA::is_nil( anHyp ))
712     THROW_SALOME_CORBA_EXCEPTION("bad hypothesis reference", SALOME::BAD_PARAM);
713
714   SMESH_Hypothesis::Hypothesis_Status status = SMESH_Hypothesis::HYP_OK;
715   try
716   {
717     TopoDS_Shape myLocSubShape;
718     //use PseudoShape in case if mesh has no shape
719     if( _impl->HasShapeToMesh() )
720       myLocSubShape = _gen_i->GeomObjectToShape( aSubShapeObject );
721     else
722       myLocSubShape = _impl->GetShapeToMesh();
723
724     const int hypId = anHyp->GetId();
725     status = _impl->RemoveHypothesis(myLocSubShape, hypId);
726     if ( !SMESH_Hypothesis::IsStatusFatal(status) )
727     {
728       // _mapHypo.erase( hypId ); EAP: hyp can be used on many sub-shapes
729       anHyp->UnRegister();
730     }
731   }
732   catch(SALOME_Exception & S_ex)
733   {
734     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
735   }
736   return status;
737 }
738
739 //=============================================================================
740 /*!
741  *
742  */
743 //=============================================================================
744
745 SMESH::ListOfHypothesis *
746 SMESH_Mesh_i::GetHypothesisList(GEOM::GEOM_Object_ptr aSubShapeObject)
747 throw(SALOME::SALOME_Exception)
748 {
749   Unexpect aCatch(SALOME_SalomeException);
750   if (MYDEBUG) MESSAGE("GetHypothesisList");
751   if (_impl->HasShapeToMesh() && CORBA::is_nil(aSubShapeObject))
752     THROW_SALOME_CORBA_EXCEPTION("bad Sub-shape reference", SALOME::BAD_PARAM);
753
754   SMESH::ListOfHypothesis_var aList = new SMESH::ListOfHypothesis();
755
756   try {
757     TopoDS_Shape myLocSubShape = _gen_i->GeomObjectToShape(aSubShapeObject);
758     if ( myLocSubShape.IsNull() && !_impl->HasShapeToMesh() )
759       myLocSubShape = _impl->GetShapeToMesh();
760     const list<const SMESHDS_Hypothesis*>& aLocalList = _impl->GetHypothesisList( myLocSubShape );
761     int i = 0, n = aLocalList.size();
762     aList->length( n );
763
764     list<const SMESHDS_Hypothesis*>::const_iterator aHyp = aLocalList.begin();
765     std::map<int, SMESH::SMESH_Hypothesis_ptr>::iterator id_hypptr;
766     for ( ; i < n && aHyp != aLocalList.end(); aHyp++ )
767     {
768       id_hypptr = _mapHypo.find( (*aHyp)->GetID() );
769       if ( id_hypptr != _mapHypo.end() )
770         aList[i++] = SMESH::SMESH_Hypothesis::_narrow( id_hypptr->second );
771     }
772     aList->length( i );
773   }
774   catch(SALOME_Exception & S_ex) {
775     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
776   }
777
778   return aList._retn();
779 }
780
781 SMESH::submesh_array* SMESH_Mesh_i::GetSubMeshes() throw (SALOME::SALOME_Exception)
782 {
783   Unexpect aCatch(SALOME_SalomeException);
784   if (MYDEBUG) MESSAGE("GetSubMeshes");
785
786   SMESH::submesh_array_var aList = new SMESH::submesh_array();
787
788   // Python Dump
789   TPythonDump aPythonDump;
790   if ( !_mapSubMeshIor.empty() )
791     aPythonDump << "[ ";
792
793   try {
794     aList->length( _mapSubMeshIor.size() );
795     int i = 0;
796     map<int, SMESH::SMESH_subMesh_ptr>::iterator it = _mapSubMeshIor.begin();
797     for ( ; it != _mapSubMeshIor.end(); it++ ) {
798       if ( CORBA::is_nil( it->second )) continue;
799       aList[i++] = SMESH::SMESH_subMesh::_duplicate( it->second );
800       // Python Dump
801       if (i > 1) aPythonDump << ", ";
802       aPythonDump << it->second;
803     }
804     aList->length( i );
805   }
806   catch(SALOME_Exception & S_ex) {
807     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
808   }
809
810   // Update Python script
811   if ( !_mapSubMeshIor.empty() )
812     aPythonDump << " ] = " << SMESH::SMESH_Mesh_var( _this() ) << ".GetSubMeshes()";
813
814   return aList._retn();
815 }
816
817 //=============================================================================
818 /*!
819  *
820  */
821 //=============================================================================
822
823 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::GetSubMesh(GEOM::GEOM_Object_ptr aSubShapeObject,
824                                                   const char*           theName )
825      throw(SALOME::SALOME_Exception)
826 {
827   Unexpect aCatch(SALOME_SalomeException);
828   if (CORBA::is_nil(aSubShapeObject))
829     THROW_SALOME_CORBA_EXCEPTION("bad Sub-shape reference", SALOME::BAD_PARAM);
830
831   SMESH::SMESH_subMesh_var subMesh;
832   SMESH::SMESH_Mesh_var    aMesh = _this();
833   try {
834     TopoDS_Shape myLocSubShape = _gen_i->GeomObjectToShape(aSubShapeObject);
835
836     //Get or Create the SMESH_subMesh object implementation
837
838     int subMeshId = _impl->GetMeshDS()->ShapeToIndex( myLocSubShape );
839
840     if ( !subMeshId && ! _impl->GetMeshDS()->IsGroupOfSubShapes( myLocSubShape ))
841     {
842       TopoDS_Iterator it( myLocSubShape );
843       if ( it.More() )
844         THROW_SALOME_CORBA_EXCEPTION("not sub-shape of the main shape", SALOME::BAD_PARAM);
845     }
846     subMesh = getSubMesh( subMeshId );
847
848     // create a new subMesh object servant if there is none for the shape
849     if ( subMesh->_is_nil() )
850       subMesh = createSubMesh( aSubShapeObject );
851     if ( _gen_i->CanPublishInStudy( subMesh ))
852     {
853       SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
854       SALOMEDS::SObject_wrap aSO =
855         _gen_i->PublishSubMesh( study, aMesh, subMesh, aSubShapeObject, theName );
856       if ( !aSO->_is_nil()) {
857         // Update Python script
858         TPythonDump() << aSO << " = " << aMesh << ".GetSubMesh( "
859                       << aSubShapeObject << ", '" << theName << "' )";
860       }
861     }
862   }
863   catch(SALOME_Exception & S_ex) {
864     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
865   }
866   return subMesh._retn();
867 }
868
869 //=============================================================================
870 /*!
871  *
872  */
873 //=============================================================================
874
875 void SMESH_Mesh_i::RemoveSubMesh( SMESH::SMESH_subMesh_ptr theSubMesh )
876   throw (SALOME::SALOME_Exception)
877 {
878   SMESH_TRY;
879
880   if ( theSubMesh->_is_nil() )
881     return;
882
883   GEOM::GEOM_Object_var aSubShapeObject;
884   SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy();
885   if ( !aStudy->_is_nil() )  {
886     // Remove submesh's SObject
887     SALOMEDS::SObject_wrap anSO = _gen_i->ObjectToSObject( aStudy, theSubMesh );
888     if ( !anSO->_is_nil() ) {
889       long aTag = SMESH_Gen_i::GetRefOnShapeTag();
890       SALOMEDS::SObject_wrap anObj, aRef;
891       if ( anSO->FindSubObject( aTag, anObj.inout() ) &&
892            anObj->ReferencedObject( aRef.inout() ))
893       {
894         CORBA::Object_var obj = aRef->GetObject();
895         aSubShapeObject = GEOM::GEOM_Object::_narrow( obj );
896       }
897       // if ( aSubShapeObject->_is_nil() ) // not published shape (IPAL13617)
898       //   aSubShapeObject = theSubMesh->GetSubShape();
899
900       SALOMEDS::StudyBuilder_var builder = aStudy->NewBuilder();
901       builder->RemoveObjectWithChildren( anSO );
902
903       // Update Python script
904       TPythonDump() << SMESH::SMESH_Mesh_var( _this() ) << ".RemoveSubMesh( " << anSO << " )";
905     }
906   }
907
908   if ( removeSubMesh( theSubMesh, aSubShapeObject.in() ))
909     if ( _preMeshInfo )
910       _preMeshInfo->ForgetOrLoad();
911
912   SMESH_CATCH( SMESH::throwCorbaException );
913 }
914
915 //=============================================================================
916 /*!
917  *
918  */
919 //=============================================================================
920
921 SMESH::SMESH_Group_ptr SMESH_Mesh_i::CreateGroup( SMESH::ElementType theElemType,
922                                                   const char*        theName )
923   throw(SALOME::SALOME_Exception)
924 {
925   Unexpect aCatch(SALOME_SalomeException);
926   if ( _preMeshInfo )
927     _preMeshInfo->FullLoadFromFile();
928
929   SMESH::SMESH_Group_var aNewGroup =
930     SMESH::SMESH_Group::_narrow( createGroup( theElemType, theName ));
931
932   if ( _gen_i->CanPublishInStudy( aNewGroup ) )
933   {
934     SMESH::SMESH_Mesh_var mesh = _this();
935     SALOMEDS::Study_var  study = _gen_i->GetCurrentStudy();
936     SALOMEDS::SObject_wrap aSO =
937       _gen_i->PublishGroup( study, mesh, aNewGroup, GEOM::GEOM_Object::_nil(), theName);
938     if ( !aSO->_is_nil())
939       // Update Python script
940       TPythonDump() << aSO << " = " << mesh << ".CreateGroup( "
941                     << theElemType << ", '" << theName << "' )";
942   }
943   return aNewGroup._retn();
944 }
945
946 //=============================================================================
947 /*!
948  *
949  */
950 //=============================================================================
951 SMESH::SMESH_GroupOnGeom_ptr
952 SMESH_Mesh_i::CreateGroupFromGEOM (SMESH::ElementType    theElemType,
953                                    const char*           theName,
954                                    GEOM::GEOM_Object_ptr theGeomObj)
955   throw(SALOME::SALOME_Exception)
956 {
957   Unexpect aCatch(SALOME_SalomeException);
958   if ( _preMeshInfo )
959     _preMeshInfo->FullLoadFromFile();
960
961   SMESH::SMESH_GroupOnGeom_var aNewGroup;
962
963   TopoDS_Shape aShape = _gen_i->GeomObjectToShape( theGeomObj );
964   if ( !aShape.IsNull() )
965   {
966     aNewGroup = 
967       SMESH::SMESH_GroupOnGeom::_narrow( createGroup( theElemType, theName, aShape ));
968
969     if ( _gen_i->CanPublishInStudy( aNewGroup ) )
970     {
971       SMESH::SMESH_Mesh_var mesh = _this();
972       SALOMEDS::Study_var  study = _gen_i->GetCurrentStudy();
973       SALOMEDS::SObject_wrap aSO =
974         _gen_i->PublishGroup( study, mesh, aNewGroup, theGeomObj, theName );
975       if ( !aSO->_is_nil())
976         TPythonDump() << aSO << " = " << mesh << ".CreateGroupFromGEOM( "
977                       << theElemType << ", '" << theName << "', " << theGeomObj << " )";
978     }
979   }
980
981   return aNewGroup._retn();
982 }
983
984 //================================================================================
985 /*!
986  * \brief Creates a group whose contents is defined by filter
987  *  \param theElemType - group type
988  *  \param theName - group name
989  *  \param theFilter - the filter
990  *  \retval SMESH::SMESH_GroupOnFilter_ptr - group defined by filter
991  */
992 //================================================================================
993
994 SMESH::SMESH_GroupOnFilter_ptr
995 SMESH_Mesh_i::CreateGroupFromFilter(SMESH::ElementType theElemType,
996                                     const char*        theName,
997                                     SMESH::Filter_ptr  theFilter )
998   throw (SALOME::SALOME_Exception)
999 {
1000   Unexpect aCatch(SALOME_SalomeException);
1001   if ( _preMeshInfo )
1002     _preMeshInfo->FullLoadFromFile();
1003
1004   if ( CORBA::is_nil( theFilter ))
1005     THROW_SALOME_CORBA_EXCEPTION("NULL filter", SALOME::BAD_PARAM);
1006
1007   SMESH_PredicatePtr predicate = SMESH_GroupOnFilter_i::GetPredicate( theFilter );
1008   if ( !predicate )
1009     THROW_SALOME_CORBA_EXCEPTION("Invalid filter", SALOME::BAD_PARAM);
1010
1011   SMESH::SMESH_GroupOnFilter_var aNewGroup = SMESH::SMESH_GroupOnFilter::_narrow
1012     ( createGroup( theElemType, theName, TopoDS_Shape(), predicate ));
1013
1014   TPythonDump pd;
1015   if ( !aNewGroup->_is_nil() )
1016     aNewGroup->SetFilter( theFilter );
1017
1018   if ( _gen_i->CanPublishInStudy( aNewGroup ) )
1019   {
1020     SMESH::SMESH_Mesh_var mesh = _this();
1021     SALOMEDS::Study_var  study = _gen_i->GetCurrentStudy();
1022     SALOMEDS::SObject_wrap aSO =
1023       _gen_i->PublishGroup( study, mesh, aNewGroup, GEOM::GEOM_Object::_nil(), theName );
1024
1025     if ( !aSO->_is_nil())
1026       pd << aSO << " = " << mesh << ".CreateGroupFromFilter( "
1027          << theElemType << ", '" << theName << "', " << theFilter << " )";
1028   }
1029   return aNewGroup._retn();
1030 }
1031
1032 //=============================================================================
1033 /*!
1034  *
1035  */
1036 //=============================================================================
1037
1038 void SMESH_Mesh_i::RemoveGroup( SMESH::SMESH_GroupBase_ptr theGroup )
1039   throw (SALOME::SALOME_Exception)
1040 {
1041   if ( theGroup->_is_nil() )
1042     return;
1043
1044   SMESH_TRY;
1045
1046   SMESH_GroupBase_i* aGroup = SMESH::DownCast<SMESH_GroupBase_i*>( theGroup );
1047   if ( !aGroup )
1048     return;
1049
1050   SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy();
1051   if ( !aStudy->_is_nil() )
1052   {
1053     SALOMEDS::SObject_wrap aGroupSO = _gen_i->ObjectToSObject( aStudy, theGroup );
1054     if ( !aGroupSO->_is_nil() )
1055     {
1056       // Update Python script
1057       TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".RemoveGroup( " << aGroupSO << " )";
1058
1059       // Remove group's SObject
1060       SALOMEDS::StudyBuilder_var builder = aStudy->NewBuilder();
1061       builder->RemoveObjectWithChildren( aGroupSO );
1062     }
1063   }
1064
1065   // Remove the group from SMESH data structures
1066   removeGroup( aGroup->GetLocalID() );
1067
1068   SMESH_CATCH( SMESH::throwCorbaException );
1069 }
1070
1071 //=============================================================================
1072 /*!
1073  *  Remove group with its contents
1074  */
1075 //=============================================================================
1076
1077 void SMESH_Mesh_i::RemoveGroupWithContents( SMESH::SMESH_GroupBase_ptr theGroup )
1078   throw (SALOME::SALOME_Exception)
1079 {
1080   SMESH_TRY;
1081   if ( _preMeshInfo )
1082     _preMeshInfo->FullLoadFromFile();
1083
1084   if ( theGroup->_is_nil() )
1085     return;
1086
1087   // Remove contents
1088   SMESH::SMESH_IDSource_var idSrc = SMESH::SMESH_IDSource::_narrow( theGroup );
1089   SMDS_ElemIteratorPtr     elemIt = GetElements( idSrc, theGroup->GetType() );
1090   while ( elemIt->more() )
1091     _impl->GetMeshDS()->RemoveElement( elemIt->next() );
1092
1093   TPythonDump pyDump; // Supress dump from RemoveGroup()
1094
1095   // Update Python script (theGroup must be alive for this)
1096   pyDump << SMESH::SMESH_Mesh_var(_this())
1097          << ".RemoveGroupWithContents( " << theGroup << " )";
1098
1099   // Remove group
1100   RemoveGroup( theGroup );
1101
1102   SMESH_CATCH( SMESH::throwCorbaException );
1103 }
1104
1105 //================================================================================
1106 /*!
1107  * \brief Get the list of groups existing in the mesh
1108  *  \retval SMESH::ListOfGroups * - list of groups
1109  */
1110 //================================================================================
1111
1112 SMESH::ListOfGroups * SMESH_Mesh_i::GetGroups() throw(SALOME::SALOME_Exception)
1113 {
1114   Unexpect aCatch(SALOME_SalomeException);
1115   if (MYDEBUG) MESSAGE("GetGroups");
1116
1117   SMESH::ListOfGroups_var aList = new SMESH::ListOfGroups();
1118
1119   // Python Dump
1120   TPythonDump aPythonDump;
1121   if ( !_mapGroups.empty() )
1122   {
1123     aPythonDump << "[ ";
1124     try {
1125       aList->length( _mapGroups.size() );
1126       int i = 0;
1127       map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.begin();
1128       for ( ; it != _mapGroups.end(); it++ ) {
1129         if ( CORBA::is_nil( it->second )) continue;
1130         aList[i++] = SMESH::SMESH_GroupBase::_duplicate( it->second );
1131         // Python Dump
1132         if (i > 1) aPythonDump << ", ";
1133         aPythonDump << it->second;
1134       }
1135       aList->length( i );
1136     }
1137     catch(SALOME_Exception & S_ex) {
1138       THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
1139     }
1140     aPythonDump << " ] = " << SMESH::SMESH_Mesh_var(_this()) << ".GetGroups()";
1141   }
1142   return aList._retn();
1143 }
1144
1145 //=============================================================================
1146 /*!
1147  *  Get number of groups existing in the mesh
1148  */
1149 //=============================================================================
1150
1151 CORBA::Long SMESH_Mesh_i::NbGroups() throw (SALOME::SALOME_Exception)
1152 {
1153   Unexpect aCatch(SALOME_SalomeException);
1154   return _mapGroups.size();
1155 }
1156
1157 //=============================================================================
1158 /*!
1159  * New group including all mesh elements present in initial groups is created.
1160  */
1161 //=============================================================================
1162
1163 SMESH::SMESH_Group_ptr SMESH_Mesh_i::UnionGroups( SMESH::SMESH_GroupBase_ptr theGroup1,
1164                                                   SMESH::SMESH_GroupBase_ptr theGroup2,
1165                                                   const char*                theName )
1166   throw (SALOME::SALOME_Exception)
1167 {
1168   SMESH::SMESH_Group_var aResGrp;
1169
1170   SMESH_TRY;
1171   if ( _preMeshInfo )
1172     _preMeshInfo->FullLoadFromFile();
1173
1174   if ( theGroup1->_is_nil() || theGroup2->_is_nil() )
1175     THROW_SALOME_CORBA_EXCEPTION("UnionGroups(): NULL Group",
1176                                  SALOME::BAD_PARAM);
1177   if ( theGroup1->GetType() != theGroup2->GetType() )
1178     THROW_SALOME_CORBA_EXCEPTION("UnionGroups(): different group types",
1179                                  SALOME::BAD_PARAM);
1180   TPythonDump pyDump;
1181
1182   // Create Union
1183   aResGrp = CreateGroup( theGroup1->GetType(), theName );
1184   if ( aResGrp->_is_nil() )
1185     return SMESH::SMESH_Group::_nil();
1186
1187   aResGrp->AddFrom( theGroup1 );
1188   aResGrp->AddFrom( theGroup2 );
1189
1190   // Update Python script
1191   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var(_this())
1192          << ".UnionGroups( " << theGroup1 << ", " << theGroup2 << ", '" << theName << "' )";
1193
1194   SMESH_CATCH( SMESH::throwCorbaException );
1195
1196   return aResGrp._retn();
1197 }
1198
1199 //=============================================================================
1200 /*!
1201  * \brief New group including all mesh elements present in initial groups is created.
1202  *  \param theGroups list of groups
1203  *  \param theName name of group to be created
1204  *  \return pointer to the new group
1205  */
1206 //=============================================================================
1207
1208 SMESH::SMESH_Group_ptr SMESH_Mesh_i::UnionListOfGroups(const SMESH::ListOfGroups& theGroups,
1209                                                        const char*                theName )
1210   throw (SALOME::SALOME_Exception)
1211 {
1212   SMESH::SMESH_Group_var aResGrp;
1213
1214   if ( _preMeshInfo )
1215     _preMeshInfo->FullLoadFromFile();
1216
1217   if ( !theName )
1218     return SMESH::SMESH_Group::_nil();
1219
1220   SMESH_TRY;
1221
1222   // check types
1223   SMESH::ElementType aType = SMESH::ALL;
1224   for ( int g = 0, n = theGroups.length(); g < n; g++ )
1225   {
1226     SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ];
1227     if ( CORBA::is_nil( aGrp ) )
1228       continue;
1229     if ( aType == SMESH::ALL )
1230       aType = aGrp->GetType();
1231     else if ( aType != aGrp->GetType() )
1232       THROW_SALOME_CORBA_EXCEPTION("UnionListOfGroups(): different group types",
1233                                    SALOME::BAD_PARAM);
1234   }
1235   if ( aType == SMESH::ALL )
1236     return SMESH::SMESH_Group::_nil();
1237
1238   TPythonDump pyDump;
1239
1240   // Create Union
1241   aResGrp = CreateGroup( aType, theName );
1242   if ( aResGrp->_is_nil() )
1243     return SMESH::SMESH_Group::_nil();
1244
1245   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var(_this()) << ".UnionListOfGroups([ ";
1246   for ( int g = 0, n = theGroups.length(); g < n; g++ )
1247   {
1248     SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ];
1249     if ( !CORBA::is_nil( aGrp ) )
1250     {
1251       aResGrp->AddFrom( aGrp );
1252       if ( g > 0 ) pyDump << ", ";
1253       pyDump << aGrp;
1254     }
1255   }
1256   pyDump << " ], '" << theName << "' )";
1257
1258   SMESH_CATCH( SMESH::throwCorbaException );
1259
1260   return aResGrp._retn();
1261 }
1262
1263 //=============================================================================
1264 /*!
1265  *  New group is created. All mesh elements that are
1266  *  present in both initial groups are added to the new one.
1267  */
1268 //=============================================================================
1269
1270 SMESH::SMESH_Group_ptr SMESH_Mesh_i::IntersectGroups( SMESH::SMESH_GroupBase_ptr theGroup1,
1271                                                       SMESH::SMESH_GroupBase_ptr theGroup2,
1272                                                       const char*                theName )
1273   throw (SALOME::SALOME_Exception)
1274 {
1275   SMESH::SMESH_Group_var aResGrp;
1276
1277   SMESH_TRY;
1278
1279   if ( _preMeshInfo )
1280     _preMeshInfo->FullLoadFromFile();
1281
1282   if ( theGroup1->_is_nil() || theGroup2->_is_nil() )
1283     THROW_SALOME_CORBA_EXCEPTION("IntersectGroups(): NULL Group",
1284                                  SALOME::BAD_PARAM);
1285   if ( theGroup1->GetType() != theGroup2->GetType() )
1286     THROW_SALOME_CORBA_EXCEPTION("IntersectGroups(): different group types",
1287                                  SALOME::BAD_PARAM);
1288   TPythonDump pyDump;
1289
1290   // Create Intersection
1291   aResGrp = CreateGroup( theGroup1->GetType(), theName );
1292   if ( aResGrp->_is_nil() )
1293     return aResGrp._retn();
1294
1295   SMESHDS_GroupBase* groupDS1 = 0;
1296   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup1 ))
1297     groupDS1 = grp_i->GetGroupDS();
1298
1299   SMESHDS_GroupBase* groupDS2 = 0;
1300   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup2 ))
1301     groupDS2 = grp_i->GetGroupDS();
1302
1303   SMESHDS_Group* resGroupDS = 0;
1304   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aResGrp ))
1305     resGroupDS = dynamic_cast<SMESHDS_Group*>( grp_i->GetGroupDS() );
1306
1307   if ( groupDS1 && groupDS2 && resGroupDS && !groupDS2->IsEmpty() )
1308   {
1309     SMDS_ElemIteratorPtr elemIt1 = groupDS1->GetElements();
1310     while ( elemIt1->more() )
1311     {
1312       const SMDS_MeshElement* e = elemIt1->next();
1313       if ( groupDS2->Contains( e ))
1314         resGroupDS->SMDSGroup().Add( e );
1315     }
1316   }
1317   // Update Python script
1318   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var(_this()) << ".IntersectGroups( "
1319          << theGroup1 << ", " << theGroup2 << ", '" << theName << "')";
1320
1321   SMESH_CATCH( SMESH::throwCorbaException );
1322
1323   return aResGrp._retn();
1324 }
1325
1326 //=============================================================================
1327 /*!
1328   \brief Intersect list of groups. New group is created. All mesh elements that 
1329   are present in all initial groups simultaneously are added to the new one.
1330   \param theGroups list of groups
1331   \param theName name of group to be created
1332   \return pointer on the group
1333 */
1334 //=============================================================================
1335 SMESH::SMESH_Group_ptr
1336 SMESH_Mesh_i::IntersectListOfGroups(const SMESH::ListOfGroups& theGroups,
1337                                     const char*                theName )
1338   throw (SALOME::SALOME_Exception)
1339 {
1340   SMESH::SMESH_Group_var aResGrp;
1341
1342   SMESH_TRY;
1343
1344   if ( _preMeshInfo )
1345     _preMeshInfo->FullLoadFromFile();
1346
1347   if ( !theName )
1348     return SMESH::SMESH_Group::_nil();
1349
1350   // check types and get SMESHDS_GroupBase's
1351   SMESH::ElementType aType = SMESH::ALL;
1352   vector< SMESHDS_GroupBase* > groupVec;
1353   for ( int g = 0, n = theGroups.length(); g < n; g++ )
1354   {
1355     SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ];
1356     if ( CORBA::is_nil( aGrp ) )
1357       continue;
1358     if ( aType == SMESH::ALL )
1359       aType = aGrp->GetType();
1360     else if ( aType != aGrp->GetType() )
1361       THROW_SALOME_CORBA_EXCEPTION("IntersectListOfGroups(): different group types",
1362                                    SALOME::BAD_PARAM);
1363
1364     if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aGrp ))
1365       if ( SMESHDS_GroupBase* grpDS = grp_i->GetGroupDS() )
1366       {
1367         if ( grpDS->IsEmpty() )
1368         {
1369           groupVec.clear();
1370           break;
1371         }
1372         groupVec.push_back( grpDS );
1373       }
1374   }
1375   if ( aType == SMESH::ALL ) // all groups are nil
1376     return SMESH::SMESH_Group::_nil();
1377
1378   TPythonDump pyDump;
1379
1380   // Create a group
1381   aResGrp = CreateGroup( aType, theName );
1382
1383   SMESHDS_Group* resGroupDS = 0;
1384   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aResGrp ))
1385     resGroupDS = dynamic_cast<SMESHDS_Group*>( grp_i->GetGroupDS() );
1386   if ( !resGroupDS || groupVec.empty() )
1387     return aResGrp._retn();
1388
1389   // Fill the group
1390   size_t i, nb = groupVec.size();
1391   SMDS_ElemIteratorPtr elemIt1 = groupVec[0]->GetElements();
1392   while ( elemIt1->more() )
1393   {
1394     const SMDS_MeshElement* e = elemIt1->next();
1395     bool inAll = true;
1396     for ( i = 1; ( i < nb && inAll ); ++i )
1397       inAll = groupVec[i]->Contains( e );
1398
1399     if ( inAll )
1400       resGroupDS->SMDSGroup().Add( e );
1401   }
1402
1403   // Update Python script
1404   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var( _this() )
1405          << ".IntersectListOfGroups( " << theGroups << ", '" << theName << "' )";
1406
1407   SMESH_CATCH( SMESH::throwCorbaException );
1408
1409   return aResGrp._retn();
1410 }
1411
1412 //=============================================================================
1413 /*! 
1414  *  New group is created. All mesh elements that are present in
1415  *  a main group but is not present in a tool group are added to the new one
1416  */
1417 //=============================================================================
1418
1419 SMESH::SMESH_Group_ptr SMESH_Mesh_i::CutGroups( SMESH::SMESH_GroupBase_ptr theGroup1,
1420                                                 SMESH::SMESH_GroupBase_ptr theGroup2,
1421                                                 const char*                theName )
1422   throw (SALOME::SALOME_Exception)
1423 {
1424   SMESH::SMESH_Group_var aResGrp;
1425
1426   SMESH_TRY;
1427
1428   if ( _preMeshInfo )
1429     _preMeshInfo->FullLoadFromFile();
1430
1431   if ( theGroup1->_is_nil() || theGroup2->_is_nil() )
1432     THROW_SALOME_CORBA_EXCEPTION("CutGroups(): NULL Group",
1433                                  SALOME::BAD_PARAM);
1434   if ( theGroup1->GetType() != theGroup2->GetType() )
1435     THROW_SALOME_CORBA_EXCEPTION("CutGroups(): different group types",
1436                                  SALOME::BAD_PARAM);
1437   TPythonDump pyDump;
1438
1439   aResGrp = CreateGroup( theGroup1->GetType(), theName );
1440   if ( aResGrp->_is_nil() )
1441     return aResGrp._retn();
1442
1443   SMESHDS_GroupBase* groupDS1 = 0;
1444   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup1 ))
1445     groupDS1 = grp_i->GetGroupDS();
1446
1447   SMESHDS_GroupBase* groupDS2 = 0;
1448   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup2 ))
1449     groupDS2 = grp_i->GetGroupDS();
1450
1451   SMESHDS_Group* resGroupDS = 0;
1452   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aResGrp ))
1453     resGroupDS = dynamic_cast<SMESHDS_Group*>( grp_i->GetGroupDS() );
1454
1455   if ( groupDS1 && groupDS2 && resGroupDS )
1456   {
1457     SMDS_ElemIteratorPtr elemIt1 = groupDS1->GetElements();
1458     while ( elemIt1->more() )
1459     {
1460       const SMDS_MeshElement* e = elemIt1->next();
1461       if ( !groupDS2->Contains( e ))
1462         resGroupDS->SMDSGroup().Add( e );
1463     }
1464   }
1465   // Update Python script
1466   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var(_this()) << ".CutGroups( "
1467          << theGroup1 << ", " << theGroup2 << ", '" << theName << "')";
1468
1469   SMESH_CATCH( SMESH::throwCorbaException );
1470
1471   return aResGrp._retn();
1472 }
1473
1474 //=============================================================================
1475 /*!
1476   \brief Cut lists of groups. New group is created. All mesh elements that are 
1477   present in main groups but do not present in tool groups are added to the new one
1478   \param theMainGroups list of main groups
1479   \param theToolGroups list of tool groups
1480   \param theName name of group to be created
1481   \return pointer on the group
1482 */
1483 //=============================================================================
1484 SMESH::SMESH_Group_ptr
1485 SMESH_Mesh_i::CutListOfGroups(const SMESH::ListOfGroups& theMainGroups, 
1486                               const SMESH::ListOfGroups& theToolGroups, 
1487                               const char*                theName )
1488   throw (SALOME::SALOME_Exception)
1489 {
1490   SMESH::SMESH_Group_var aResGrp;
1491
1492   SMESH_TRY;
1493
1494   if ( _preMeshInfo )
1495     _preMeshInfo->FullLoadFromFile();
1496
1497   if ( !theName )
1498     return SMESH::SMESH_Group::_nil();
1499
1500   // check types and get SMESHDS_GroupBase's
1501   SMESH::ElementType aType = SMESH::ALL;
1502   vector< SMESHDS_GroupBase* >   toolGroupVec;
1503   vector< SMDS_ElemIteratorPtr > mainIterVec;
1504
1505   for ( int g = 0, n = theMainGroups.length(); g < n; g++ )
1506   {
1507     SMESH::SMESH_GroupBase_var aGrp = theMainGroups[ g ];
1508     if ( CORBA::is_nil( aGrp ) )
1509       continue;
1510     if ( aType == SMESH::ALL )
1511       aType = aGrp->GetType();
1512     else if ( aType != aGrp->GetType() )
1513       THROW_SALOME_CORBA_EXCEPTION("CutListOfGroups(): different group types",
1514                                    SALOME::BAD_PARAM);
1515     if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aGrp ))
1516       if ( SMESHDS_GroupBase* grpDS = grp_i->GetGroupDS() )
1517         if ( !grpDS->IsEmpty() )
1518           mainIterVec.push_back( grpDS->GetElements() );
1519   }
1520   if ( aType == SMESH::ALL ) // all main groups are nil
1521     return SMESH::SMESH_Group::_nil();
1522   if ( mainIterVec.empty() ) // all main groups are empty
1523     return aResGrp._retn();
1524
1525   for ( int g = 0, n = theToolGroups.length(); g < n; g++ )
1526   {
1527     SMESH::SMESH_GroupBase_var aGrp = theToolGroups[ g ];
1528     if ( CORBA::is_nil( aGrp ) )
1529       continue;
1530     if ( aType != aGrp->GetType() )
1531       THROW_SALOME_CORBA_EXCEPTION("CutListOfGroups(): different group types",
1532                                    SALOME::BAD_PARAM);
1533     if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aGrp ))
1534       if ( SMESHDS_GroupBase* grpDS = grp_i->GetGroupDS() )
1535         toolGroupVec.push_back( grpDS );
1536   }
1537
1538   TPythonDump pyDump;
1539
1540   // Create a group
1541   aResGrp = CreateGroup( aType, theName );
1542
1543   SMESHDS_Group* resGroupDS = 0;
1544   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aResGrp ))
1545     resGroupDS = dynamic_cast<SMESHDS_Group*>( grp_i->GetGroupDS() );
1546   if ( !resGroupDS )
1547     return aResGrp._retn();
1548
1549   // Fill the group
1550   size_t i, nb = toolGroupVec.size();
1551   SMDS_ElemIteratorPtr mainElemIt
1552     ( new SMDS_IteratorOnIterators
1553       < const SMDS_MeshElement*, vector< SMDS_ElemIteratorPtr > >( mainIterVec ));
1554   while ( mainElemIt->more() )
1555   {
1556     const SMDS_MeshElement* e = mainElemIt->next();
1557     bool isIn = false;
1558     for ( i = 0; ( i < nb && !isIn ); ++i )
1559       isIn = toolGroupVec[i]->Contains( e );
1560
1561     if ( !isIn )
1562       resGroupDS->SMDSGroup().Add( e );
1563   }
1564
1565   // Update Python script
1566   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var( _this() )
1567          << ".CutListOfGroups( " << theMainGroups
1568          << theToolGroups << ", '" << theName << "' )";
1569
1570   SMESH_CATCH( SMESH::throwCorbaException );
1571
1572   return aResGrp._retn();
1573 }
1574
1575 //=============================================================================
1576 /*!
1577   \brief Create groups of entities from existing groups of superior dimensions 
1578   System
1579   1) extract all nodes from each group,
1580   2) combine all elements of specified dimension laying on these nodes.
1581   \param theGroups list of source groups 
1582   \param theElemType dimension of elements 
1583   \param theName name of new group
1584   \return pointer on new group
1585   *
1586   IMP 19939
1587 */
1588 //=============================================================================
1589
1590 SMESH::SMESH_Group_ptr
1591 SMESH_Mesh_i::CreateDimGroup(const SMESH::ListOfGroups& theGroups, 
1592                              SMESH::ElementType         theElemType, 
1593                              const char*                theName )
1594   throw (SALOME::SALOME_Exception)
1595 {
1596   SMESH::SMESH_Group_var aResGrp;
1597
1598   SMESH_TRY;
1599   if ( _preMeshInfo )
1600     _preMeshInfo->FullLoadFromFile();
1601
1602   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
1603
1604   if ( !theName || !aMeshDS )
1605     return SMESH::SMESH_Group::_nil();
1606
1607   SMDSAbs_ElementType anElemType = (SMDSAbs_ElementType)theElemType;
1608
1609   // Create a group
1610
1611   TPythonDump pyDump;
1612
1613   aResGrp = CreateGroup( theElemType, theName );
1614   if ( aResGrp->_is_nil() )
1615     return SMESH::SMESH_Group::_nil();
1616
1617   SMESHDS_GroupBase* groupBaseDS =
1618     SMESH::DownCast<SMESH_GroupBase_i*>( aResGrp )->GetGroupDS();
1619   SMDS_MeshGroup& resGroupCore = static_cast< SMESHDS_Group* >( groupBaseDS )->SMDSGroup();
1620
1621   for ( int g = 0, n = theGroups.length(); g < n; g++ ) // loop on theGroups
1622   {
1623     SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ];
1624     if ( CORBA::is_nil( aGrp ) )
1625       continue;
1626
1627     groupBaseDS = SMESH::DownCast<SMESH_GroupBase_i*>( aGrp )->GetGroupDS();
1628     SMDS_ElemIteratorPtr elIt = groupBaseDS->GetElements();
1629
1630     if ( theElemType == SMESH::NODE ) // get all nodes of elements
1631     {
1632       while ( elIt->more() ) {
1633         const SMDS_MeshElement* el = elIt->next();
1634         SMDS_ElemIteratorPtr nIt = el->nodesIterator();
1635         while ( nIt->more() )
1636           resGroupCore.Add( nIt->next() );
1637       }
1638     }
1639     else // get elements of theElemType based on nodes of every element of group
1640     {
1641       while ( elIt->more() )
1642       {
1643         const SMDS_MeshElement* el = elIt->next(); // an element of group
1644         TIDSortedElemSet elNodes( el->begin_nodes(), el->end_nodes() );
1645         TIDSortedElemSet checkedElems;
1646         SMDS_ElemIteratorPtr nIt = el->nodesIterator();
1647         while ( nIt->more() )
1648         {
1649           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nIt->next() );
1650           SMDS_ElemIteratorPtr elOfTypeIt = n->GetInverseElementIterator( anElemType );
1651           // check nodes of elements of theElemType around el
1652           while ( elOfTypeIt->more() )
1653           {
1654             const SMDS_MeshElement* elOfType = elOfTypeIt->next();
1655             if ( !checkedElems.insert( elOfType ).second ) continue;
1656
1657             SMDS_ElemIteratorPtr nIt2 = elOfType->nodesIterator();
1658             bool allNodesOK = true;
1659             while ( nIt2->more() && allNodesOK )
1660               allNodesOK = elNodes.count( nIt2->next() );
1661             if ( allNodesOK )
1662               resGroupCore.Add( elOfType );
1663           }
1664         }
1665       }
1666     }
1667   }
1668
1669   // Update Python script
1670   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var( _this())
1671          << ".CreateDimGroup( "
1672          << theGroups << ", " << theElemType << ", '" << theName << "' )";
1673
1674   SMESH_CATCH( SMESH::throwCorbaException );
1675
1676   return aResGrp._retn();
1677 }
1678
1679 //================================================================================
1680 /*!
1681  * \brief Remember GEOM group data
1682  */
1683 //================================================================================
1684
1685 void SMESH_Mesh_i::addGeomGroupData(GEOM::GEOM_Object_ptr theGeomObj,
1686                                     CORBA::Object_ptr     theSmeshObj)
1687 {
1688   if ( CORBA::is_nil( theGeomObj ) || theGeomObj->GetType() != GEOM_GROUP )
1689     return;
1690   // group SO
1691   SALOMEDS::Study_var    study   = _gen_i->GetCurrentStudy();
1692   SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( study, theGeomObj );
1693   if ( groupSO->_is_nil() )
1694     return;
1695   // group indices
1696   GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine();
1697   GEOM::GEOM_IGroupOperations_wrap groupOp =
1698     geomGen->GetIGroupOperations( _gen_i->GetCurrentStudyID() );
1699   GEOM::ListOfLong_var ids = groupOp->GetObjects( theGeomObj );
1700
1701   // store data
1702   _geomGroupData.push_back( TGeomGroupData() );
1703   TGeomGroupData & groupData = _geomGroupData.back();
1704   // entry
1705   CORBA::String_var entry = groupSO->GetID();
1706   groupData._groupEntry = entry.in();
1707   // indices
1708   for ( int i = 0; i < ids->length(); ++i )
1709     groupData._indices.insert( ids[i] );
1710   // SMESH object
1711   groupData._smeshObject = CORBA::Object::_duplicate( theSmeshObj );
1712 }
1713
1714 //================================================================================
1715 /*!
1716  * Remove GEOM group data relating to removed smesh object
1717  */
1718 //================================================================================
1719
1720 void SMESH_Mesh_i::removeGeomGroupData(CORBA::Object_ptr theSmeshObj)
1721 {
1722   list<TGeomGroupData>::iterator
1723     data = _geomGroupData.begin(), dataEnd = _geomGroupData.end();
1724   for ( ; data != dataEnd; ++data ) {
1725     if ( theSmeshObj->_is_equivalent( data->_smeshObject )) {
1726       _geomGroupData.erase( data );
1727       return;
1728     }
1729   }
1730 }
1731
1732 //================================================================================
1733 /*!
1734  * \brief Return new group contents if it has been changed and update group data
1735  */
1736 //================================================================================
1737
1738 TopoDS_Shape SMESH_Mesh_i::newGroupShape( TGeomGroupData & groupData)
1739 {
1740   TopoDS_Shape newShape;
1741
1742   // get geom group
1743   SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
1744   if ( study->_is_nil() ) return newShape; // means "not changed"
1745   SALOMEDS::SObject_wrap groupSO = study->FindObjectID( groupData._groupEntry.c_str() );
1746   if ( !groupSO->_is_nil() )
1747   {
1748     CORBA::Object_var groupObj = _gen_i->SObjectToObject( groupSO );
1749     if ( CORBA::is_nil( groupObj )) return newShape;
1750     GEOM::GEOM_Object_var geomGroup = GEOM::GEOM_Object::_narrow( groupObj );
1751
1752     // get indices of group items
1753     set<int> curIndices;
1754     GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine();
1755     GEOM::GEOM_IGroupOperations_wrap groupOp =
1756       geomGen->GetIGroupOperations( _gen_i->GetCurrentStudyID() );
1757     GEOM::ListOfLong_var   ids = groupOp->GetObjects( geomGroup );
1758     for ( int i = 0; i < ids->length(); ++i )
1759       curIndices.insert( ids[i] );
1760
1761     if ( groupData._indices == curIndices )
1762       return newShape; // group not changed
1763
1764     // update data
1765     groupData._indices = curIndices;
1766
1767     GEOM_Client* geomClient = _gen_i->GetShapeReader();
1768     if ( !geomClient ) return newShape;
1769     CORBA::String_var groupIOR = geomGen->GetStringFromIOR( geomGroup );
1770     geomClient->RemoveShapeFromBuffer( groupIOR.in() );
1771     newShape = _gen_i->GeomObjectToShape( geomGroup );
1772   }
1773
1774   if ( newShape.IsNull() ) {
1775     // geom group becomes empty - return empty compound
1776     TopoDS_Compound compound;
1777     BRep_Builder().MakeCompound(compound);
1778     newShape = compound;
1779   }
1780   return newShape;
1781 }
1782
1783 namespace
1784 {
1785   //-----------------------------------------------------------------------------
1786   /*!
1787    * \brief Storage of shape and index used in CheckGeomGroupModif()
1788    */
1789   struct TIndexedShape
1790   {
1791     int          _index;
1792     TopoDS_Shape _shape;
1793     TIndexedShape( int i, const TopoDS_Shape& s ):_index(i), _shape(s) {}
1794   };
1795   //-----------------------------------------------------------------------------
1796   /*!
1797    * \brief Data to re-create a group on geometry
1798    */
1799   struct TGroupOnGeomData
1800   {
1801     int                 _oldID;
1802     int                 _shapeID;
1803     SMDSAbs_ElementType _type;
1804     std::string         _name;
1805     Quantity_Color      _color;
1806   };
1807 }
1808
1809 //=============================================================================
1810 /*!
1811  * \brief Update data if geometry changes
1812  *
1813  * Issue 0022501
1814  */
1815 //=============================================================================
1816
1817 void SMESH_Mesh_i::CheckGeomModif()
1818 {
1819   if ( !_impl->HasShapeToMesh() ) return;
1820
1821   SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
1822   if ( study->_is_nil() ) return;
1823
1824   GEOM::GEOM_Object_var mainGO = _gen_i->ShapeToGeomObject( _impl->GetShapeToMesh() );
1825   if ( mainGO->_is_nil() ) return;
1826
1827   if ( mainGO->GetType() == GEOM_GROUP )
1828   {
1829     CheckGeomGroupModif();
1830     return;
1831   }
1832   if ( mainGO->GetTick() == _mainShapeTick )
1833     return;
1834
1835   GEOM_Client* geomClient = _gen_i->GetShapeReader();
1836   if ( !geomClient ) return;
1837   GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine();
1838   if ( geomGen->_is_nil() ) return;
1839
1840   CORBA::String_var ior = geomGen->GetStringFromIOR( mainGO );
1841   geomClient->RemoveShapeFromBuffer( ior.in() );
1842
1843   // Update data taking into account that
1844   // all sub-shapes change but IDs of sub-shapes remain
1845
1846   _impl->Clear();
1847   TopoDS_Shape newShape = _gen_i->GeomObjectToShape( mainGO );
1848   if ( newShape.IsNull() )
1849     return;
1850
1851   _mainShapeTick = mainGO->GetTick();
1852
1853   SMESHDS_Mesh * meshDS = _impl->GetMeshDS();
1854
1855   // store data of groups on geometry
1856   vector< TGroupOnGeomData > groupsData;
1857   const set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
1858   groupsData.reserve( groups.size() );
1859   set<SMESHDS_GroupBase*>::const_iterator g = groups.begin();
1860   for ( ; g != groups.end(); ++g )
1861     if ( const SMESHDS_GroupOnGeom* group = dynamic_cast< SMESHDS_GroupOnGeom* >( *g ))
1862     {
1863       TGroupOnGeomData data;
1864       data._oldID   = group->GetID();
1865       data._shapeID = meshDS->ShapeToIndex( group->GetShape() );
1866       data._type    = group->GetType();
1867       data._name    = group->GetStoreName();
1868       data._color   = group->GetColor();
1869       groupsData.push_back( data );
1870     }
1871   // store assigned hypotheses
1872   vector< pair< int, THypList > > ids2Hyps;
1873   const ShapeToHypothesis & hyps = meshDS->GetHypotheses();
1874   for ( ShapeToHypothesis::Iterator s2hyps( hyps ); s2hyps.More(); s2hyps.Next() )
1875   {
1876     const TopoDS_Shape& s = s2hyps.Key();
1877     const THypList&  hyps = s2hyps.ChangeValue();
1878     ids2Hyps.push_back( make_pair( meshDS->ShapeToIndex( s ), hyps ));
1879   }
1880
1881   // change shape to mesh
1882   _impl->ShapeToMesh( TopoDS_Shape() );
1883   _impl->ShapeToMesh( newShape );
1884
1885   // re-assign hypotheses
1886   for ( size_t i = 0; i < ids2Hyps.size(); ++i )
1887   {
1888     const TopoDS_Shape& s = meshDS->IndexToShape( ids2Hyps[i].first );
1889     const THypList&  hyps = ids2Hyps[i].second;
1890     THypList::const_iterator h = hyps.begin();
1891     for ( ; h != hyps.end(); ++h )
1892       _impl->AddHypothesis( s, (*h)->GetID() );
1893   }
1894
1895   // restore groups
1896   for ( size_t i = 0; i < groupsData.size(); ++i )
1897   {
1898     const TGroupOnGeomData& data = groupsData[i];
1899
1900     map<int, SMESH::SMESH_GroupBase_ptr>::iterator i2g = _mapGroups.find( data._oldID );
1901     if ( i2g == _mapGroups.end() ) continue;
1902
1903     SMESH_GroupBase_i* gr_i = SMESH::DownCast<SMESH_GroupBase_i*>( i2g->second );
1904     if ( !gr_i ) continue;
1905
1906     int id;
1907     SMESH_Group* g = _impl->AddGroup( data._type, data._name.c_str(), id,
1908                                       meshDS->IndexToShape( data._shapeID ));
1909     if ( !g )
1910     {
1911       _mapGroups.erase( i2g );
1912     }
1913     else
1914     {
1915       gr_i->changeLocalId( id );
1916       g->GetGroupDS()->SetColor( data._color );
1917     }
1918   }
1919
1920   // update _mapSubMesh
1921   map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
1922   for ( ; i_sm != _mapSubMesh.end(); ++i_sm )
1923     i_sm->second = _impl->GetSubMesh( meshDS->IndexToShape( i_sm->first ));
1924
1925 }
1926
1927 //=============================================================================
1928 /*!
1929  * \brief Update objects depending on changed geom groups
1930  *
1931  * NPAL16168: geometrical group edition from a submesh don't modifiy mesh computation
1932  * issue 0020210: Update of a smesh group after modification of the associated geom group
1933  */
1934 //=============================================================================
1935
1936 void SMESH_Mesh_i::CheckGeomGroupModif()
1937 {
1938   if ( !_impl->HasShapeToMesh() ) return;
1939
1940   SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
1941   if ( study->_is_nil() ) return;
1942
1943   CORBA::Long nbEntities = NbNodes() + NbElements();
1944
1945   // Check if group contents changed
1946
1947   typedef map< string, TopoDS_Shape > TEntry2Geom;
1948   TEntry2Geom newGroupContents;
1949
1950   list<TGeomGroupData>::iterator
1951     data = _geomGroupData.begin(), dataEnd = _geomGroupData.end();
1952   for ( ; data != dataEnd; ++data )
1953   {
1954     pair< TEntry2Geom::iterator, bool > it_new =
1955       newGroupContents.insert( make_pair( data->_groupEntry, TopoDS_Shape() ));
1956     bool processedGroup    = !it_new.second;
1957     TopoDS_Shape& newShape = it_new.first->second;
1958     if ( !processedGroup )
1959       newShape = newGroupShape( *data );
1960     if ( newShape.IsNull() )
1961       continue; // no changes
1962
1963     if ( _preMeshInfo )
1964       _preMeshInfo->ForgetOrLoad();
1965
1966     if ( processedGroup ) { // update group indices
1967       list<TGeomGroupData>::iterator data2 = data;
1968       for ( --data2; data2->_groupEntry != data->_groupEntry; --data2) {}
1969       data->_indices = data2->_indices;
1970     }
1971
1972     // Update SMESH objects according to new GEOM group contents
1973
1974     SMESH::SMESH_subMesh_var submesh = SMESH::SMESH_subMesh::_narrow( data->_smeshObject );
1975     if ( !submesh->_is_nil() ) // -------------- Sub mesh ---------------------
1976     {
1977       int oldID = submesh->GetId();
1978       if ( !_mapSubMeshIor.count( oldID ))
1979         continue;
1980       TopoDS_Shape oldShape = _mapSubMesh[oldID]->GetSubShape();
1981
1982       // update hypotheses
1983       list <const SMESHDS_Hypothesis * > hyps = _impl->GetHypothesisList(oldShape);
1984       list <const SMESHDS_Hypothesis * >::iterator hypIt;
1985       for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
1986       {
1987         _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
1988         _impl->AddHypothesis   ( newShape, (*hypIt)->GetID());
1989       }
1990       // care of submeshes
1991       SMESH_subMesh* newSubmesh = _impl->GetSubMesh( newShape );
1992       int newID = newSubmesh->GetId();
1993       if ( newID != oldID ) {
1994         _mapSubMesh   [ newID ] = newSubmesh;
1995         _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
1996         _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
1997         _mapSubMesh.   erase(oldID);
1998         _mapSubMesh_i. erase(oldID);
1999         _mapSubMeshIor.erase(oldID);
2000         _mapSubMesh_i [ newID ]->changeLocalId( newID );
2001       }
2002       continue;
2003     }
2004
2005     SMESH::SMESH_GroupOnGeom_var smeshGroup =
2006       SMESH::SMESH_GroupOnGeom::_narrow( data->_smeshObject );
2007     if ( !smeshGroup->_is_nil() ) // ------------ GROUP -----------------------
2008     {
2009       SMESH_GroupOnGeom_i* group_i = SMESH::DownCast<SMESH_GroupOnGeom_i*>( smeshGroup );
2010       if ( group_i ) {
2011         ::SMESH_Group* group = _impl->GetGroup( group_i->GetLocalID() );
2012         SMESHDS_GroupOnGeom* ds = static_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() );
2013         ds->SetShape( newShape );
2014       }
2015       continue;
2016     }
2017
2018     SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( data->_smeshObject );
2019     if ( !mesh->_is_nil() ) // -------------- MESH ----------------------------
2020     {
2021       // Remove groups and submeshes basing on removed sub-shapes
2022
2023       TopTools_MapOfShape newShapeMap;
2024       TopoDS_Iterator shapeIt( newShape );
2025       for ( ; shapeIt.More(); shapeIt.Next() )
2026         newShapeMap.Add( shapeIt.Value() );
2027
2028       SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
2029       for ( shapeIt.Initialize( meshDS->ShapeToMesh() ); shapeIt.More(); shapeIt.Next() )
2030       {
2031         if ( newShapeMap.Contains( shapeIt.Value() ))
2032           continue;
2033         TopTools_IndexedMapOfShape oldShapeMap;
2034         TopExp::MapShapes( shapeIt.Value(), oldShapeMap );
2035         for ( int i = 1; i <= oldShapeMap.Extent(); ++i )
2036         {
2037           const TopoDS_Shape& oldShape = oldShapeMap(i);
2038           int oldInd = meshDS->ShapeToIndex( oldShape );
2039           // -- submeshes --
2040           map<int, SMESH::SMESH_subMesh_ptr>::iterator i_smIor = _mapSubMeshIor.find( oldInd );
2041           if ( i_smIor != _mapSubMeshIor.end() ) {
2042             RemoveSubMesh( i_smIor->second ); // one submesh per shape index
2043           }
2044           // --- groups ---
2045           map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.begin();
2046           for ( ; i_grp != _mapGroups.end(); ++i_grp )
2047           {
2048             // check if a group bases on oldInd shape
2049             SMESHDS_GroupOnGeom* grpOnGeom = 0;
2050             if ( ::SMESH_Group* g = _impl->GetGroup( i_grp->first ))
2051               grpOnGeom = dynamic_cast<SMESHDS_GroupOnGeom*>( g->GetGroupDS() );
2052             if ( grpOnGeom && oldShape.IsSame( grpOnGeom->GetShape() ))
2053             { // remove
2054               RemoveGroup( i_grp->second ); // several groups can base on same shape
2055               i_grp = _mapGroups.begin(); // _mapGroups changed - restart iteration
2056             }
2057           }
2058         }
2059       }
2060       // Reassign hypotheses and update groups after setting the new shape to mesh
2061
2062       // collect anassigned hypotheses
2063       typedef list< pair< TIndexedShape, list<const SMESHDS_Hypothesis*> > > TShapeHypList;
2064       list <const SMESHDS_Hypothesis * >::const_iterator hypIt;
2065       TShapeHypList assignedHyps;
2066       for ( int i = 1; i <= meshDS->MaxShapeIndex(); ++i )
2067       {
2068         const TopoDS_Shape& oldShape = meshDS->IndexToShape(i);
2069         list<const SMESHDS_Hypothesis*> hyps = meshDS->GetHypothesis( oldShape );// copy
2070         if ( !hyps.empty() ) {
2071           assignedHyps.push_back( make_pair( TIndexedShape(i,oldShape), hyps ));
2072           for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2073             _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
2074         }
2075       }
2076       // collect shapes supporting groups
2077       typedef list < pair< TIndexedShape, SMDSAbs_ElementType > > TShapeTypeList;
2078       TShapeTypeList groupData;
2079       const set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
2080       set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2081       for ( ; grIt != groups.end(); ++grIt )
2082       {
2083         if ( SMESHDS_GroupOnGeom* gog = dynamic_cast<SMESHDS_GroupOnGeom*>( *grIt ))
2084           groupData.push_back
2085             ( make_pair( TIndexedShape( gog->GetID(),gog->GetShape()), gog->GetType()));
2086       }
2087       // set new shape to mesh -> DS of submeshes and geom groups is deleted
2088       _impl->ShapeToMesh( newShape );
2089       
2090       // reassign hypotheses
2091       TShapeHypList::iterator indS_hyps = assignedHyps.begin();
2092       for ( ; indS_hyps != assignedHyps.end(); ++indS_hyps )
2093       {
2094         TIndexedShape&                   geom = indS_hyps->first;
2095         list<const SMESHDS_Hypothesis*>& hyps = indS_hyps->second;
2096         int oldID = geom._index;
2097         int newID = meshDS->ShapeToIndex( geom._shape );
2098         if ( oldID == 1 ) { // main shape
2099           newID = 1;
2100           geom._shape = newShape;
2101         }
2102         if ( !newID )
2103           continue;
2104         for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2105           _impl->AddHypothesis( geom._shape, (*hypIt)->GetID());
2106         // care of submeshes
2107         SMESH_subMesh* newSubmesh = _impl->GetSubMesh( geom._shape );
2108         if ( newID != oldID ) {
2109           _mapSubMesh   [ newID ] = newSubmesh;
2110           _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2111           _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2112           _mapSubMesh.   erase(oldID);
2113           _mapSubMesh_i. erase(oldID);
2114           _mapSubMeshIor.erase(oldID);
2115           _mapSubMesh_i [ newID ]->changeLocalId( newID );
2116         }
2117       }
2118       // recreate groups
2119       TShapeTypeList::iterator geomType = groupData.begin();
2120       for ( ; geomType != groupData.end(); ++geomType )
2121       {
2122         const TIndexedShape& geom = geomType->first;
2123         int oldID = geom._index;
2124         if ( _mapGroups.find( oldID ) == _mapGroups.end() )
2125           continue;
2126         // get group name
2127         SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( study,_mapGroups[oldID] );
2128         CORBA::String_var      name    = groupSO->GetName();
2129         // update
2130         SMESH_GroupBase_i*  group_i    = SMESH::DownCast<SMESH_GroupBase_i*>(_mapGroups[oldID] );
2131         int newID;
2132         if ( group_i && _impl->AddGroup( geomType->second, name.in(), newID, geom._shape ))
2133           group_i->changeLocalId( newID );
2134       }
2135
2136       break; // everything has been updated
2137
2138     } // update mesh
2139   } // loop on group data
2140
2141   // Update icons
2142
2143   CORBA::Long newNbEntities = NbNodes() + NbElements();
2144   list< SALOMEDS::SObject_wrap > soToUpdateIcons;
2145   if ( newNbEntities != nbEntities )
2146   {
2147     // Add all SObjects with icons to soToUpdateIcons
2148     soToUpdateIcons.push_back( _gen_i->ObjectToSObject( study, _this() )); // mesh
2149
2150     for (map<int, SMESH::SMESH_subMesh_ptr>::iterator i_sm = _mapSubMeshIor.begin();
2151          i_sm != _mapSubMeshIor.end(); ++i_sm ) // submeshes
2152       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( study, i_sm->second ));
2153
2154     for ( map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
2155           i_gr != _mapGroups.end(); ++i_gr ) // groups
2156       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( study, i_gr->second ));
2157   }
2158
2159   list< SALOMEDS::SObject_wrap >::iterator so = soToUpdateIcons.begin();
2160   for ( ; so != soToUpdateIcons.end(); ++so )
2161     _gen_i->SetPixMap( *so, "ICON_SMESH_TREE_MESH_WARN" );
2162 }
2163
2164 //=============================================================================
2165 /*!
2166  * \brief Create standalone group from a group on geometry or filter
2167  */
2168 //=============================================================================
2169
2170 SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupBase_ptr theGroup )
2171   throw (SALOME::SALOME_Exception)
2172 {
2173   SMESH::SMESH_Group_var aGroup;
2174
2175   SMESH_TRY;
2176
2177   if ( _preMeshInfo )
2178     _preMeshInfo->FullLoadFromFile();
2179
2180   if ( theGroup->_is_nil() )
2181     return aGroup._retn();
2182
2183   SMESH_GroupBase_i* aGroupToRem = SMESH::DownCast<SMESH_GroupBase_i*>( theGroup );
2184   if ( !aGroupToRem )
2185     return aGroup._retn();
2186
2187   const bool isOnFilter = ( SMESH::DownCast< SMESH_GroupOnFilter_i* > ( theGroup ));
2188
2189   const int anId = aGroupToRem->GetLocalID();
2190   if ( !_impl->ConvertToStandalone( anId ) )
2191     return aGroup._retn();
2192   removeGeomGroupData( theGroup );
2193
2194   SMESH_GroupBase_i* aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
2195
2196   // remove old instance of group from own map
2197   { SMESH::SMESH_GroupBase_var var( _mapGroups[anId] ); } // decref CORBA object
2198   _mapGroups.erase( anId );
2199
2200   SALOMEDS::StudyBuilder_var builder;
2201   SALOMEDS::SObject_wrap     aGroupSO;
2202   SALOMEDS::Study_var        aStudy = _gen_i->GetCurrentStudy();
2203   if ( !aStudy->_is_nil() ) {
2204     builder  = aStudy->NewBuilder();
2205     aGroupSO = _gen_i->ObjectToSObject( aStudy, theGroup );
2206     if ( !aGroupSO->_is_nil() )
2207     {
2208       // remove reference to geometry
2209       SALOMEDS::ChildIterator_wrap chItr = aStudy->NewChildIterator(aGroupSO);
2210       for ( ; chItr->More(); chItr->Next() )
2211         // Remove group's child SObject
2212         builder->RemoveObject( chItr->Value() );
2213
2214       // Update Python script
2215       TPythonDump() << aGroupSO << " = " << SMESH::SMESH_Mesh_var(_this())
2216                     << ".ConvertToStandalone( " << aGroupSO << " )";
2217
2218       // change icon of Group on Filter
2219       if ( isOnFilter )
2220       {
2221         SMESH::array_of_ElementType_var elemTypes = aGroupImpl->GetTypes();
2222         const int isEmpty = ( elemTypes->length() == 0 );
2223         if ( !isEmpty )
2224         {
2225           SALOMEDS::GenericAttribute_wrap anAttr =
2226             builder->FindOrCreateAttribute( aGroupSO, "AttributePixMap" );
2227           SALOMEDS::AttributePixMap_wrap pm = anAttr;
2228           pm->SetPixMap( "ICON_SMESH_TREE_GROUP" );
2229         }
2230       }
2231     }
2232   }
2233
2234   // remember new group in own map
2235   aGroup = SMESH::SMESH_Group::_narrow( aGroupImpl->_this() );
2236   _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
2237
2238   // register CORBA object for persistence
2239   _gen_i->RegisterObject( aGroup );
2240
2241   CORBA::String_var ior = _gen_i->GetORB()->object_to_string( aGroup );
2242   builder->SetIOR( aGroupSO, ior.in() ); //  == aGroup->Register();
2243   //aGroup->Register();
2244   aGroupToRem->UnRegister();
2245
2246   SMESH_CATCH( SMESH::throwCorbaException );
2247
2248   return aGroup._retn();
2249 }
2250
2251 //=============================================================================
2252 /*!
2253  *
2254  */
2255 //=============================================================================
2256
2257 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::createSubMesh( GEOM::GEOM_Object_ptr theSubShapeObject )
2258 {
2259   if(MYDEBUG) MESSAGE( "createSubMesh" );
2260   TopoDS_Shape  myLocSubShape = _gen_i->GeomObjectToShape(theSubShapeObject);
2261   ::SMESH_subMesh * mySubMesh = _impl->GetSubMesh(myLocSubShape);
2262   const int         subMeshId = mySubMesh->GetId();
2263
2264   SMESH_subMesh_i * subMeshServant = new SMESH_subMesh_i(myPOA, _gen_i, this, subMeshId);
2265   SMESH::SMESH_subMesh_var subMesh = subMeshServant->_this();
2266
2267   _mapSubMesh   [subMeshId] = mySubMesh;
2268   _mapSubMesh_i [subMeshId] = subMeshServant;
2269   _mapSubMeshIor[subMeshId] = SMESH::SMESH_subMesh::_duplicate( subMesh );
2270
2271   subMeshServant->Register();
2272
2273   // register CORBA object for persistence
2274   int nextId = _gen_i->RegisterObject( subMesh );
2275   if(MYDEBUG) { MESSAGE( "Add submesh to map with id = "<< nextId); }
2276   else        { nextId = 0; } // avoid "unused variable" warning
2277
2278   // to track changes of GEOM groups
2279   addGeomGroupData( theSubShapeObject, subMesh );
2280
2281   return subMesh._retn();
2282 }
2283
2284 //=======================================================================
2285 //function : getSubMesh
2286 //purpose  :
2287 //=======================================================================
2288
2289 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::getSubMesh(int shapeID)
2290 {
2291   map<int, SMESH::SMESH_subMesh_ptr>::iterator it = _mapSubMeshIor.find( shapeID );
2292   if ( it == _mapSubMeshIor.end() )
2293     return SMESH::SMESH_subMesh::_nil();
2294
2295   return SMESH::SMESH_subMesh::_duplicate( (*it).second );
2296 }
2297
2298 //=============================================================================
2299 /*!
2300  *
2301  */
2302 //=============================================================================
2303
2304 bool SMESH_Mesh_i::removeSubMesh (SMESH::SMESH_subMesh_ptr theSubMesh,
2305                                   GEOM::GEOM_Object_ptr    theSubShapeObject )
2306 {
2307   bool isHypChanged = false;
2308   if ( theSubMesh->_is_nil() /*|| theSubShapeObject->_is_nil()*/ )
2309     return isHypChanged;
2310
2311   const int subMeshId = theSubMesh->GetId();
2312
2313   if ( theSubShapeObject->_is_nil() )  // not published shape (IPAL13617)
2314   {
2315     if ( _mapSubMesh.find( subMeshId ) != _mapSubMesh.end())
2316     {
2317       TopoDS_Shape S = _mapSubMesh[ subMeshId ]->GetSubShape();
2318       if ( !S.IsNull() )
2319       {
2320         list<const SMESHDS_Hypothesis*> hyps = _impl->GetHypothesisList( S );
2321         isHypChanged = !hyps.empty();
2322         list<const SMESHDS_Hypothesis*>::const_iterator hyp = hyps.begin();
2323         for ( ; hyp != hyps.end(); ++hyp )
2324           _impl->RemoveHypothesis(S, (*hyp)->GetID());
2325       }
2326     }
2327   }
2328   else
2329   {
2330     try {
2331       SMESH::ListOfHypothesis_var aHypList = GetHypothesisList( theSubShapeObject );
2332       isHypChanged = ( aHypList->length() > 0 );
2333       for ( int i = 0, n = aHypList->length(); i < n; i++ ) {
2334         removeHypothesis( theSubShapeObject, aHypList[i] );
2335       }
2336     }
2337     catch( const SALOME::SALOME_Exception& ) {
2338       INFOS("SMESH_Mesh_i::removeSubMesh(): exception caught!");
2339     }
2340     removeGeomGroupData( theSubShapeObject );
2341   }
2342
2343   // remove a servant
2344   std::map<int, SMESH_subMesh_i*>::iterator id_smi = _mapSubMesh_i.find( subMeshId );
2345   if ( id_smi != _mapSubMesh_i.end() )
2346     id_smi->second->UnRegister();
2347
2348   // remove a CORBA object
2349   std::map<int, SMESH::SMESH_subMesh_ptr>::iterator id_smptr = _mapSubMeshIor.find( subMeshId );
2350   if ( id_smptr != _mapSubMeshIor.end() )
2351     SMESH::SMESH_subMesh_var( id_smptr->second );
2352
2353   _mapSubMesh.erase(subMeshId);
2354   _mapSubMesh_i.erase(subMeshId);
2355   _mapSubMeshIor.erase(subMeshId);
2356
2357   return isHypChanged;
2358 }
2359
2360 //=============================================================================
2361 /*!
2362  *
2363  */
2364 //=============================================================================
2365
2366 SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType        theElemType,
2367                                                       const char*               theName,
2368                                                       const TopoDS_Shape&       theShape,
2369                                                       const SMESH_PredicatePtr& thePredicate )
2370 {
2371   std::string newName;
2372   if ( !theName || strlen( theName ) == 0 )
2373   {
2374     std::set< std::string > presentNames;
2375     std::map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator i_gr = _mapGroups.begin();
2376     for ( ; i_gr != _mapGroups.end(); ++i_gr )
2377     {
2378       CORBA::String_var name = i_gr->second->GetName();
2379       presentNames.insert( name.in() );
2380     }
2381     do {
2382       newName = "noname_Group_" + SMESH_Comment( presentNames.size() + 1 );
2383     } while ( !presentNames.insert( newName ).second );
2384     theName = newName.c_str();
2385   }
2386   int anId;
2387   SMESH::SMESH_GroupBase_var aGroup;
2388   if ( _impl->AddGroup( (SMDSAbs_ElementType)theElemType, theName, anId, theShape, thePredicate ))
2389   {
2390     SMESH_GroupBase_i* aGroupImpl;
2391     if ( !theShape.IsNull() )
2392       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
2393     else if ( thePredicate )
2394       aGroupImpl = new SMESH_GroupOnFilter_i( SMESH_Gen_i::GetPOA(), this, anId );
2395     else
2396       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
2397
2398     aGroup = aGroupImpl->_this();
2399     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
2400     aGroupImpl->Register();
2401
2402     // register CORBA object for persistence
2403     int nextId = _gen_i->RegisterObject( aGroup );
2404     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
2405     else        { nextId = 0; } // avoid "unused variable" warning in release mode
2406
2407     // to track changes of GEOM groups
2408     if ( !theShape.IsNull() ) {
2409       GEOM::GEOM_Object_var geom = _gen_i->ShapeToGeomObject( theShape );
2410       addGeomGroupData( geom, aGroup );
2411     }
2412   }
2413   return aGroup._retn();
2414 }
2415
2416 //=============================================================================
2417 /*!
2418  * SMESH_Mesh_i::removeGroup
2419  *
2420  * Should be called by ~SMESH_Group_i()
2421  */
2422 //=============================================================================
2423
2424 void SMESH_Mesh_i::removeGroup( const int theId )
2425 {
2426   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::removeGroup()" );
2427   if ( _mapGroups.find( theId ) != _mapGroups.end() ) {
2428     SMESH::SMESH_GroupBase_var group = _mapGroups[theId];
2429     _mapGroups.erase( theId );
2430     removeGeomGroupData( group );
2431     if ( !_impl->RemoveGroup( theId ))
2432     {
2433       // it seems to be a call up from _impl caused by hyp modification (issue 0020918)
2434       RemoveGroup( group );
2435     }
2436     group->UnRegister();
2437   }
2438 }
2439
2440 //=============================================================================
2441 /*!
2442  *
2443  */
2444 //=============================================================================
2445
2446 SMESH::log_array * SMESH_Mesh_i::GetLog(CORBA::Boolean clearAfterGet)
2447   throw(SALOME::SALOME_Exception)
2448 {
2449   SMESH::log_array_var aLog;
2450
2451   SMESH_TRY;
2452   if ( _preMeshInfo )
2453     _preMeshInfo->FullLoadFromFile();
2454
2455   list < SMESHDS_Command * >logDS = _impl->GetLog();
2456   aLog = new SMESH::log_array;
2457   int indexLog = 0;
2458   int lg = logDS.size();
2459   SCRUTE(lg);
2460   aLog->length(lg);
2461   list < SMESHDS_Command * >::iterator its = logDS.begin();
2462   while(its != logDS.end()){
2463     SMESHDS_Command *com = *its;
2464     int comType = com->GetType();
2465     //SCRUTE(comType);
2466     int lgcom = com->GetNumber();
2467     //SCRUTE(lgcom);
2468     const list < int >&intList = com->GetIndexes();
2469     int inum = intList.size();
2470     //SCRUTE(inum);
2471     list < int >::const_iterator ii = intList.begin();
2472     const list < double >&coordList = com->GetCoords();
2473     int rnum = coordList.size();
2474     //SCRUTE(rnum);
2475     list < double >::const_iterator ir = coordList.begin();
2476     aLog[indexLog].commandType = comType;
2477     aLog[indexLog].number = lgcom;
2478     aLog[indexLog].coords.length(rnum);
2479     aLog[indexLog].indexes.length(inum);
2480     for(int i = 0; i < rnum; i++){
2481       aLog[indexLog].coords[i] = *ir;
2482       //MESSAGE(" "<<i<<" "<<ir.Value());
2483       ir++;
2484     }
2485     for(int i = 0; i < inum; i++){
2486       aLog[indexLog].indexes[i] = *ii;
2487       //MESSAGE(" "<<i<<" "<<ii.Value());
2488       ii++;
2489     }
2490     indexLog++;
2491     its++;
2492   }
2493   if(clearAfterGet)
2494     _impl->ClearLog();
2495
2496   SMESH_CATCH( SMESH::throwCorbaException );
2497
2498   return aLog._retn();
2499 }
2500
2501
2502 //=============================================================================
2503 /*!
2504  *
2505  */
2506 //=============================================================================
2507
2508 void SMESH_Mesh_i::ClearLog() throw(SALOME::SALOME_Exception)
2509 {
2510   SMESH_TRY;
2511   _impl->ClearLog();
2512   SMESH_CATCH( SMESH::throwCorbaException );
2513 }
2514
2515 //=============================================================================
2516 /*!
2517  *
2518  */
2519 //=============================================================================
2520
2521 CORBA::Long SMESH_Mesh_i::GetId()throw(SALOME::SALOME_Exception)
2522 {
2523   return _id;
2524 }
2525
2526 //=============================================================================
2527 /*!
2528  *
2529  */
2530 //=============================================================================
2531
2532 CORBA::Long SMESH_Mesh_i::GetStudyId()throw(SALOME::SALOME_Exception)
2533 {
2534   return _studyId;
2535 }
2536
2537 //=============================================================================
2538 namespace
2539 {
2540   //!< implementation of struct used to call methods of SMESH_Mesh_i from SMESH_Mesh
2541   // issue 0020918: groups removal is caused by hyp modification
2542   // issue 0021208: to forget not loaded mesh data at hyp modification
2543   struct TCallUp_i : public SMESH_Mesh::TCallUp
2544   {
2545     SMESH_Mesh_i* _mesh;
2546     TCallUp_i(SMESH_Mesh_i* mesh):_mesh(mesh) {}
2547     virtual void RemoveGroup (const int theGroupID) { _mesh->removeGroup( theGroupID ); }
2548     virtual void HypothesisModified ()              { _mesh->onHypothesisModified(); }
2549     virtual void Load ()                            { _mesh->Load(); }
2550   };
2551 }
2552
2553 //================================================================================
2554 /*!
2555  * \brief callback from _impl to forget not loaded mesh data (issue 0021208)
2556  */
2557 //================================================================================
2558
2559 void SMESH_Mesh_i::onHypothesisModified()
2560 {
2561   if ( _preMeshInfo )
2562     _preMeshInfo->ForgetOrLoad();
2563 }
2564
2565 //=============================================================================
2566 /*!
2567  *
2568  */
2569 //=============================================================================
2570
2571 void SMESH_Mesh_i::SetImpl(::SMESH_Mesh * impl)
2572 {
2573   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::SetImpl");
2574   _impl = impl;
2575   if ( _impl )
2576     _impl->SetCallUp( new TCallUp_i(this));
2577 }
2578
2579 //=============================================================================
2580 /*!
2581  *
2582  */
2583 //=============================================================================
2584
2585 ::SMESH_Mesh & SMESH_Mesh_i::GetImpl()
2586 {
2587   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::GetImpl()");
2588   return *_impl;
2589 }
2590
2591 //=============================================================================
2592 /*!
2593  * Return mesh editor
2594  */
2595 //=============================================================================
2596
2597 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditor()
2598   throw (SALOME::SALOME_Exception)
2599 {
2600   SMESH::SMESH_MeshEditor_var aMeshEdVar;
2601
2602   SMESH_TRY;
2603   if ( _preMeshInfo )
2604     _preMeshInfo->FullLoadFromFile();
2605
2606   // Create MeshEditor
2607   if ( !_editor )
2608     _editor = new SMESH_MeshEditor_i( this, false );
2609   aMeshEdVar = _editor->_this();
2610
2611   // Update Python script
2612   TPythonDump() << _editor << " = "
2613                 << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshEditor()";
2614
2615   SMESH_CATCH( SMESH::throwCorbaException );
2616
2617   return aMeshEdVar._retn();
2618 }
2619
2620 //=============================================================================
2621 /*!
2622  * Return mesh edition previewer
2623  */
2624 //=============================================================================
2625
2626 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditPreviewer()
2627   throw (SALOME::SALOME_Exception)
2628 {
2629   SMESH::SMESH_MeshEditor_var aMeshEdVar;
2630
2631   SMESH_TRY;
2632   if ( _preMeshInfo )
2633     _preMeshInfo->FullLoadFromFile();
2634
2635   if ( !_previewEditor )
2636     _previewEditor = new SMESH_MeshEditor_i( this, true );
2637   aMeshEdVar = _previewEditor->_this();
2638
2639   SMESH_CATCH( SMESH::throwCorbaException );
2640
2641   return aMeshEdVar._retn();
2642 }
2643
2644 //================================================================================
2645 /*!
2646  * \brief Return true if the mesh has been edited since a last total re-compute
2647  *        and those modifications may prevent successful partial re-compute
2648  */
2649 //================================================================================
2650
2651 CORBA::Boolean SMESH_Mesh_i::HasModificationsToDiscard() throw(SALOME::SALOME_Exception)
2652 {
2653   Unexpect aCatch(SALOME_SalomeException);
2654   return _impl->HasModificationsToDiscard();
2655 }
2656
2657 //================================================================================
2658 /*!
2659  * \brief Returns a random unique color
2660  */
2661 //================================================================================
2662
2663 static SALOMEDS::Color getUniqueColor( const std::list<SALOMEDS::Color>& theReservedColors )
2664 {
2665   const int MAX_ATTEMPTS = 100;
2666   int cnt = 0;
2667   double tolerance = 0.5;
2668   SALOMEDS::Color col;
2669
2670   bool ok = false;
2671   while ( !ok ) {
2672     // generate random color
2673     double red    = (double)rand() / RAND_MAX;
2674     double green  = (double)rand() / RAND_MAX;
2675     double blue   = (double)rand() / RAND_MAX;
2676     // check existence in the list of the existing colors
2677     bool matched = false;
2678     std::list<SALOMEDS::Color>::const_iterator it;
2679     for ( it = theReservedColors.begin(); it != theReservedColors.end() && !matched; ++it ) {
2680       SALOMEDS::Color color = *it;
2681       double tol = fabs( color.R - red ) + fabs( color.G - green ) + fabs( color.B  - blue  );
2682       matched = tol < tolerance;
2683     }
2684     if ( (cnt+1) % 20 == 0 ) tolerance = tolerance/2;
2685     ok = ( ++cnt == MAX_ATTEMPTS ) || !matched;
2686     col.R = red;
2687     col.G = green;
2688     col.B = blue;
2689   }
2690   return col;
2691 }
2692
2693 //=============================================================================
2694 /*!
2695  * Sets auto-color mode. If it is on, groups get unique random colors
2696  */
2697 //=============================================================================
2698
2699 void SMESH_Mesh_i::SetAutoColor(CORBA::Boolean theAutoColor) throw(SALOME::SALOME_Exception)
2700 {
2701   Unexpect aCatch(SALOME_SalomeException);
2702   _impl->SetAutoColor(theAutoColor);
2703
2704   TPythonDump pyDump; // not to dump group->SetColor() from below code
2705   pyDump << SMESH::SMESH_Mesh_var(_this()) <<".SetAutoColor( "<<theAutoColor<<" )";
2706
2707   std::list<SALOMEDS::Color> aReservedColors;
2708   map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.begin();
2709   for ( ; it != _mapGroups.end(); it++ ) {
2710     if ( CORBA::is_nil( it->second )) continue;
2711     SALOMEDS::Color aColor = getUniqueColor( aReservedColors );
2712     it->second->SetColor( aColor );
2713     aReservedColors.push_back( aColor );
2714   }
2715 }
2716
2717 //=============================================================================
2718 /*!
2719  * Returns true if auto-color mode is on
2720  */
2721 //=============================================================================
2722
2723 CORBA::Boolean SMESH_Mesh_i::GetAutoColor() throw(SALOME::SALOME_Exception)
2724 {
2725   Unexpect aCatch(SALOME_SalomeException);
2726   return _impl->GetAutoColor();
2727 }
2728
2729 //=============================================================================
2730 /*!
2731  *  Checks if there are groups with equal names
2732  */
2733 //=============================================================================
2734
2735 CORBA::Boolean SMESH_Mesh_i::HasDuplicatedGroupNamesMED()
2736 {
2737   return _impl->HasDuplicatedGroupNamesMED();
2738 }
2739
2740 //================================================================================
2741 /*!
2742  * \brief Care of a file before exporting mesh into it
2743  */
2744 //================================================================================
2745
2746 void SMESH_Mesh_i::PrepareForWriting (const char* file, bool overwrite)
2747 {
2748   TCollection_AsciiString aFullName ((char*)file);
2749   OSD_Path aPath (aFullName);
2750   OSD_File aFile (aPath);
2751   if (aFile.Exists()) {
2752     // existing filesystem node
2753     if (aFile.KindOfFile() == OSD_FILE) {
2754       if (aFile.IsWriteable()) {
2755         if (overwrite) {
2756           aFile.Reset();
2757           aFile.Remove();
2758         }
2759         if (aFile.Failed()) {
2760           TCollection_AsciiString msg ("File ");
2761           msg += aFullName + " cannot be replaced.";
2762           THROW_SALOME_CORBA_EXCEPTION(msg.ToCString(), SALOME::BAD_PARAM);
2763         }
2764       } else {
2765         TCollection_AsciiString msg ("File ");
2766         msg += aFullName + " cannot be overwritten.";
2767         THROW_SALOME_CORBA_EXCEPTION(msg.ToCString(), SALOME::BAD_PARAM);
2768       }
2769     } else {
2770       TCollection_AsciiString msg ("Location ");
2771       msg += aFullName + " is not a file.";
2772       THROW_SALOME_CORBA_EXCEPTION(msg.ToCString(), SALOME::BAD_PARAM);
2773     }
2774   } else {
2775     // nonexisting file; check if it can be created
2776     aFile.Reset();
2777     aFile.Build(OSD_WriteOnly, OSD_Protection());
2778     if (aFile.Failed()) {
2779       TCollection_AsciiString msg ("You cannot create the file ");
2780       msg += aFullName + ". Check the directory existance and access rights.";
2781       THROW_SALOME_CORBA_EXCEPTION(msg.ToCString(), SALOME::BAD_PARAM);
2782     } else {
2783       aFile.Close();
2784       aFile.Remove();
2785     }
2786   }
2787 }
2788
2789 //================================================================================
2790 /*!
2791  * \brief Prepares a file for export and pass names of mesh groups from study to mesh DS
2792  *  \param file - file name
2793  *  \param overwrite - to erase the file or not
2794  *  \retval string - mesh name
2795  */
2796 //================================================================================
2797
2798 string SMESH_Mesh_i::prepareMeshNameAndGroups(const char*    file,
2799                                               CORBA::Boolean overwrite)
2800 {
2801   // Perform Export
2802   PrepareForWriting(file, overwrite);
2803   string aMeshName = "Mesh";
2804   SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy();
2805   if ( !aStudy->_is_nil() ) {
2806     SALOMEDS::SObject_wrap aMeshSO = _gen_i->ObjectToSObject( aStudy, _this() );
2807     if ( !aMeshSO->_is_nil() ) {
2808       CORBA::String_var name = aMeshSO->GetName();
2809       aMeshName = name;
2810       // asv : 27.10.04 : fix of 6903: check for StudyLocked before adding attributes
2811       if ( !aStudy->GetProperties()->IsLocked() )
2812       {
2813         SALOMEDS::GenericAttribute_wrap anAttr;
2814         SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder();
2815         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeExternalFileDef");
2816         SALOMEDS::AttributeExternalFileDef_wrap aFileName = anAttr;
2817         ASSERT(!aFileName->_is_nil());
2818         aFileName->SetValue(file);
2819         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeFileType");
2820         SALOMEDS::AttributeFileType_wrap aFileType = anAttr;
2821         ASSERT(!aFileType->_is_nil());
2822         aFileType->SetValue("FICHIERMED");
2823       }
2824     }
2825   }
2826   // Update Python script
2827   // set name of mesh before export
2828   TPythonDump() << _gen_i << ".SetName("
2829                 << SMESH::SMESH_Mesh_var(_this()) << ", '" << aMeshName.c_str() << "')";
2830
2831   // check names of groups
2832   checkGroupNames();
2833
2834   return aMeshName;
2835 }
2836
2837 //================================================================================
2838 /*!
2839  * \brief Export to med file
2840  */
2841 //================================================================================
2842
2843 void SMESH_Mesh_i::ExportToMEDX (const char*        file,
2844                                  CORBA::Boolean     auto_groups,
2845                                  SMESH::MED_VERSION theVersion,
2846                                  CORBA::Boolean     overwrite,
2847                                  CORBA::Boolean     autoDimension)
2848   throw(SALOME::SALOME_Exception)
2849 {
2850   SMESH_TRY;
2851   if ( _preMeshInfo )
2852     _preMeshInfo->FullLoadFromFile();
2853
2854   string aMeshName = prepareMeshNameAndGroups(file, overwrite);
2855   _impl->ExportMED( file, aMeshName.c_str(), auto_groups, theVersion, 0, autoDimension );
2856
2857   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportToMEDX( r'"
2858                 << file << "', " << auto_groups << ", "
2859                 << theVersion << ", " << overwrite << ", "
2860                 << autoDimension << " )";
2861
2862   SMESH_CATCH( SMESH::throwCorbaException );
2863 }
2864
2865 //================================================================================
2866 /*!
2867  * \brief Export a mesh to a med file
2868  */
2869 //================================================================================
2870
2871 void SMESH_Mesh_i::ExportToMED (const char*        file,
2872                                 CORBA::Boolean     auto_groups,
2873                                 SMESH::MED_VERSION theVersion)
2874   throw(SALOME::SALOME_Exception)
2875 {
2876   ExportToMEDX(file,auto_groups,theVersion,true);
2877 }
2878
2879 //================================================================================
2880 /*!
2881  * \brief Export a mesh to a med file
2882  */
2883 //================================================================================
2884
2885 void SMESH_Mesh_i::ExportMED (const char* file,
2886                               CORBA::Boolean auto_groups)
2887   throw(SALOME::SALOME_Exception)
2888 {
2889   ExportToMEDX(file,auto_groups,SMESH::MED_V2_2,true);
2890 }
2891
2892 //================================================================================
2893 /*!
2894  * \brief Export a mesh to a SAUV file
2895  */
2896 //================================================================================
2897
2898 void SMESH_Mesh_i::ExportSAUV (const char* file,
2899                                CORBA::Boolean auto_groups)
2900   throw(SALOME::SALOME_Exception)
2901 {
2902   Unexpect aCatch(SALOME_SalomeException);
2903   if ( _preMeshInfo )
2904     _preMeshInfo->FullLoadFromFile();
2905
2906   string aMeshName = prepareMeshNameAndGroups(file, true);
2907   TPythonDump() << SMESH::SMESH_Mesh_var( _this())
2908                 << ".ExportSAUV( r'" << file << "', " << auto_groups << " )";
2909   _impl->ExportSAUV(file, aMeshName.c_str(), auto_groups);
2910 }
2911
2912
2913 //================================================================================
2914 /*!
2915  * \brief Export a mesh to a DAT file
2916  */
2917 //================================================================================
2918
2919 void SMESH_Mesh_i::ExportDAT (const char *file)
2920   throw(SALOME::SALOME_Exception)
2921 {
2922   Unexpect aCatch(SALOME_SalomeException);
2923   if ( _preMeshInfo )
2924     _preMeshInfo->FullLoadFromFile();
2925
2926   // Update Python script
2927   // check names of groups
2928   checkGroupNames();
2929   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportDAT( r'" << file << "' )";
2930
2931   // Perform Export
2932   PrepareForWriting(file);
2933   _impl->ExportDAT(file);
2934 }
2935
2936 //================================================================================
2937 /*!
2938  * \brief Export a mesh to an UNV file
2939  */
2940 //================================================================================
2941
2942 void SMESH_Mesh_i::ExportUNV (const char *file)
2943   throw(SALOME::SALOME_Exception)
2944 {
2945   Unexpect aCatch(SALOME_SalomeException);
2946   if ( _preMeshInfo )
2947     _preMeshInfo->FullLoadFromFile();
2948
2949   // Update Python script
2950   // check names of groups
2951   checkGroupNames();
2952   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportUNV( r'" << file << "' )";
2953
2954   // Perform Export
2955   PrepareForWriting(file);
2956   _impl->ExportUNV(file);
2957 }
2958
2959 //================================================================================
2960 /*!
2961  * \brief Export a mesh to an STL file
2962  */
2963 //================================================================================
2964
2965 void SMESH_Mesh_i::ExportSTL (const char *file, const bool isascii)
2966   throw(SALOME::SALOME_Exception)
2967 {
2968   Unexpect aCatch(SALOME_SalomeException);
2969   if ( _preMeshInfo )
2970     _preMeshInfo->FullLoadFromFile();
2971
2972   // Update Python script
2973   // check names of groups
2974   checkGroupNames();
2975   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
2976                 << ".ExportSTL( r'" << file << "', " << isascii << " )";
2977
2978   // Perform Export
2979   PrepareForWriting(file);
2980   _impl->ExportSTL(file, isascii);
2981 }
2982
2983 //================================================================================
2984 /*!
2985  * \brief Export a part of mesh to a med file
2986  */
2987 //================================================================================
2988
2989 void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
2990                                    const char*               file,
2991                                    CORBA::Boolean            auto_groups,
2992                                    SMESH::MED_VERSION        version,
2993                                    CORBA::Boolean            overwrite,
2994                                    CORBA::Boolean            autoDimension,
2995                                    const GEOM::ListOfFields& fields,
2996                                    const char*               geomAssocFields)
2997   throw (SALOME::SALOME_Exception)
2998 {
2999   SMESH_TRY;
3000   if ( _preMeshInfo )
3001     _preMeshInfo->FullLoadFromFile();
3002
3003   // check fields
3004   bool have0dField = false;
3005   if ( fields.length() > 0 )
3006   {
3007     GEOM::GEOM_Object_var shapeToMesh = GetShapeToMesh();
3008     if ( shapeToMesh->_is_nil() )
3009       THROW_SALOME_CORBA_EXCEPTION( "No shape to mesh", SALOME::INTERNAL_ERROR );
3010
3011     for ( size_t i = 0; i < fields.length(); ++i )
3012     {
3013       if ( fields[i]->GetDataType() == GEOM::FDT_String )
3014         THROW_SALOME_CORBA_EXCEPTION
3015           ( "Export of string fields is not supported", SALOME::BAD_PARAM);
3016       GEOM::GEOM_Object_var fieldShape = fields[i]->GetShape();
3017       if ( fieldShape->_is_nil() )
3018         THROW_SALOME_CORBA_EXCEPTION( "Null shape under a field", SALOME::INTERNAL_ERROR );
3019       if ( !fieldShape->IsSame( shapeToMesh ) )
3020         THROW_SALOME_CORBA_EXCEPTION
3021           ( "Field defined not on shape", SALOME::BAD_PARAM);
3022       if ( fields[i]->GetDimension() == 0 )
3023         have0dField = true;
3024     }
3025     if ( geomAssocFields )
3026       for ( int i = 0; geomAssocFields[i]; ++i )
3027         switch ( geomAssocFields[i] ) {
3028         case 'v':case 'e':case 'f':case 's': break;
3029         case 'V':case 'E':case 'F':case 'S': break;
3030         default: THROW_SALOME_CORBA_EXCEPTION
3031             ( "geomAssocFields can include only [vefs] characters", SALOME::BAD_PARAM);
3032         }
3033   }
3034
3035   SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
3036
3037   // write mesh
3038
3039   string aMeshName = "Mesh";
3040   SMESHUtils::Deleter< SMESH_MeshPartDS > tmpDSDeleter(0);
3041   if ( CORBA::is_nil( meshPart ) ||
3042        SMESH::DownCast< SMESH_Mesh_i* >( meshPart ))
3043   {
3044     aMeshName = prepareMeshNameAndGroups(file, overwrite);
3045     _impl->ExportMED( file, aMeshName.c_str(), auto_groups,
3046                       version, 0, autoDimension, have0dField);
3047     meshDS = _impl->GetMeshDS();
3048   }
3049   else
3050   {
3051     if ( _preMeshInfo )
3052       _preMeshInfo->FullLoadFromFile();
3053
3054     PrepareForWriting(file, overwrite);
3055
3056     SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy();
3057     if ( !aStudy->_is_nil() ) {
3058       SALOMEDS::SObject_wrap SO = _gen_i->ObjectToSObject( aStudy, meshPart );
3059       if ( !SO->_is_nil() ) {
3060         CORBA::String_var name = SO->GetName();
3061         aMeshName = name;
3062       }
3063     }
3064     SMESH_MeshPartDS* partDS = new SMESH_MeshPartDS( meshPart );
3065     _impl->ExportMED( file, aMeshName.c_str(), auto_groups,
3066                       version, partDS, autoDimension, have0dField);
3067     meshDS = tmpDSDeleter._obj = partDS;
3068   }
3069
3070   // write fields
3071
3072   if ( _impl->HasShapeToMesh() )
3073   {
3074     DriverMED_W_Field fieldWriter;
3075     fieldWriter.SetFile( file );
3076     fieldWriter.SetMeshName( aMeshName );
3077     fieldWriter.AddODOnVertices( have0dField );
3078
3079     exportMEDFields( fieldWriter, meshDS, fields, geomAssocFields );
3080   }
3081
3082   // dump
3083   GEOM::ListOfGBO_var goList = new GEOM::ListOfGBO;
3084   goList->length( fields.length() );
3085   for ( size_t i = 0; i < fields.length(); ++i )
3086   {
3087     GEOM::GEOM_BaseObject_var gbo = GEOM::GEOM_BaseObject::_narrow( fields[i] );
3088     goList[i] = gbo;
3089   }
3090   TPythonDump() << _this() << ".ExportPartToMED( "
3091                 << meshPart << ", r'" << file << "', "
3092                 << auto_groups << ", " << version << ", " << overwrite << ", "
3093                 << autoDimension << ", " << goList
3094                 << ", '" << ( geomAssocFields ? geomAssocFields : "" ) << "'" << " )";
3095
3096   SMESH_CATCH( SMESH::throwCorbaException );
3097 }
3098
3099 //================================================================================
3100 /*!
3101  * Write GEOM fields to MED file
3102  */
3103 //================================================================================
3104
3105 void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
3106                                     SMESHDS_Mesh*             meshDS,
3107                                     const GEOM::ListOfFields& fields,
3108                                     const char*               geomAssocFields)
3109 {
3110 #define METH "SMESH_Mesh_i::exportMEDFields() "
3111
3112   if (( fields.length() < 1 ) &&
3113       ( !geomAssocFields || !geomAssocFields[0] ))
3114     return;
3115
3116   std::vector< double > dblVals( meshDS->MaxShapeIndex()+1 );
3117   std::vector< int >    intVals( meshDS->MaxShapeIndex()+1 );
3118   std::vector< int >    subIdsByDim[ 4 ];
3119   const double noneDblValue = 0.;
3120   const double noneIntValue = 0;
3121
3122   for ( size_t iF = 0; iF < fields.length(); ++iF )
3123   {
3124     // set field data
3125
3126     int dim = fields[ iF ]->GetDimension();
3127     SMDSAbs_ElementType elemType;
3128     TopAbs_ShapeEnum    shapeType;
3129     switch ( dim ) {
3130     case 0: elemType = SMDSAbs_0DElement; shapeType = TopAbs_VERTEX; break;
3131     case 1: elemType = SMDSAbs_Edge;      shapeType = TopAbs_EDGE;   break;
3132     case 2: elemType = SMDSAbs_Face;      shapeType = TopAbs_FACE;   break;
3133     case 3: elemType = SMDSAbs_Volume;    shapeType = TopAbs_SOLID;  break;
3134     default:
3135       continue; // skip fields on whole shape
3136     }
3137     GEOM::field_data_type dataType = fields[ iF ]->GetDataType();
3138     if ( dataType == GEOM::FDT_String )
3139       continue;
3140     GEOM::ListOfLong_var stepIDs = fields[ iF ]->GetSteps();
3141     if ( stepIDs->length() < 1 )
3142       continue;
3143     GEOM::string_array_var comps = fields[ iF ]->GetComponents();
3144     if ( comps->length() < 1 )
3145       continue;
3146     CORBA::String_var       name = fields[ iF ]->GetName();
3147
3148     if ( !fieldWriter.Set( meshDS,
3149                            name.in(),
3150                            elemType,
3151                            comps->length(),
3152                            ( dataType == GEOM::FDT_Int )))
3153       continue;
3154
3155     for ( size_t iC = 0; iC < comps->length(); ++iC )
3156       fieldWriter.SetCompName( iC, comps[ iC ].in() );
3157
3158     // find sub-shape IDs
3159
3160     std::vector< int >& subIds = subIdsByDim[ dim ];
3161     if ( subIds.empty() )
3162       for ( int id = 1; id <= meshDS->MaxShapeIndex(); ++id )
3163         if ( meshDS->IndexToShape( id ).ShapeType() == shapeType )
3164           subIds.push_back( id );
3165
3166     // write steps
3167
3168     SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
3169     if ( !elemIt )
3170       continue;
3171
3172     for ( size_t iS = 0; iS < stepIDs->length(); ++iS )
3173     {
3174       GEOM::GEOM_FieldStep_var step = fields[ iF ]->GetStep( stepIDs[ iS ]);
3175       if ( step->_is_nil() )
3176         continue;
3177
3178       CORBA::Long stamp = step->GetStamp();
3179       CORBA::Long id    = step->GetID();
3180       fieldWriter.SetDtIt( int( stamp ), int( id ));
3181
3182       // fill dblVals or intVals
3183       switch ( dataType )
3184       {
3185       case GEOM::FDT_Double:
3186       {
3187         GEOM::GEOM_DoubleFieldStep_var dblStep = GEOM::GEOM_DoubleFieldStep::_narrow( step );
3188         if ( dblStep->_is_nil() ) continue;
3189         GEOM::ListOfDouble_var vv = dblStep->GetValues();
3190         if ( vv->length() != subIds.size() )
3191           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
3192         for ( size_t i = 0; i < vv->length(); ++i )
3193           dblVals[ subIds[ i ]] = vv[ i ];
3194         break;
3195       }
3196       case GEOM::FDT_Int:
3197       {
3198         GEOM::GEOM_IntFieldStep_var intStep = GEOM::GEOM_IntFieldStep::_narrow( step );
3199         if ( intStep->_is_nil() ) continue;
3200         GEOM::ListOfLong_var vv = intStep->GetValues();
3201         if ( vv->length() != subIds.size() )
3202           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
3203         for ( size_t i = 0; i < vv->length(); ++i )
3204           intVals[ subIds[ i ]] = (int) vv[ i ];
3205         break;
3206       }
3207       case GEOM::FDT_Bool:
3208       {
3209         GEOM::GEOM_BoolFieldStep_var boolStep = GEOM::GEOM_BoolFieldStep::_narrow( step );
3210         if ( boolStep->_is_nil() ) continue;
3211         GEOM::short_array_var vv = boolStep->GetValues();
3212         if ( vv->length() != subIds.size() )
3213           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
3214         for ( size_t i = 0; i < vv->length(); ++i )
3215           intVals[ subIds[ i ]] = (int) vv[ i ];
3216         break;
3217       }
3218       default: continue;
3219       }
3220
3221       // pass values to fieldWriter
3222       elemIt = fieldWriter.GetOrderedElems();
3223       if ( dataType == GEOM::FDT_Double )
3224         while ( elemIt->more() )
3225         {
3226           const SMDS_MeshElement* e = elemIt->next();
3227           const int shapeID = e->getshapeId();
3228           if ( shapeID < 1 || shapeID >= dblVals.size() )