Salome HOME
22501: [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       g->GetGroupDS()->SetColor( data._color );
1916       gr_i->changeLocalId( id );
1917       _mapGroups[ id ] = i2g->second;
1918       if ( data._oldID != id )
1919         _mapGroups.erase( i2g );
1920     }
1921   }
1922
1923   // update _mapSubMesh
1924   map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
1925   for ( ; i_sm != _mapSubMesh.end(); ++i_sm )
1926     i_sm->second = _impl->GetSubMesh( meshDS->IndexToShape( i_sm->first ));
1927
1928 }
1929
1930 //=============================================================================
1931 /*!
1932  * \brief Update objects depending on changed geom groups
1933  *
1934  * NPAL16168: geometrical group edition from a submesh don't modifiy mesh computation
1935  * issue 0020210: Update of a smesh group after modification of the associated geom group
1936  */
1937 //=============================================================================
1938
1939 void SMESH_Mesh_i::CheckGeomGroupModif()
1940 {
1941   if ( !_impl->HasShapeToMesh() ) return;
1942
1943   SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
1944   if ( study->_is_nil() ) return;
1945
1946   CORBA::Long nbEntities = NbNodes() + NbElements();
1947
1948   // Check if group contents changed
1949
1950   typedef map< string, TopoDS_Shape > TEntry2Geom;
1951   TEntry2Geom newGroupContents;
1952
1953   list<TGeomGroupData>::iterator
1954     data = _geomGroupData.begin(), dataEnd = _geomGroupData.end();
1955   for ( ; data != dataEnd; ++data )
1956   {
1957     pair< TEntry2Geom::iterator, bool > it_new =
1958       newGroupContents.insert( make_pair( data->_groupEntry, TopoDS_Shape() ));
1959     bool processedGroup    = !it_new.second;
1960     TopoDS_Shape& newShape = it_new.first->second;
1961     if ( !processedGroup )
1962       newShape = newGroupShape( *data );
1963     if ( newShape.IsNull() )
1964       continue; // no changes
1965
1966     if ( _preMeshInfo )
1967       _preMeshInfo->ForgetOrLoad();
1968
1969     if ( processedGroup ) { // update group indices
1970       list<TGeomGroupData>::iterator data2 = data;
1971       for ( --data2; data2->_groupEntry != data->_groupEntry; --data2) {}
1972       data->_indices = data2->_indices;
1973     }
1974
1975     // Update SMESH objects according to new GEOM group contents
1976
1977     SMESH::SMESH_subMesh_var submesh = SMESH::SMESH_subMesh::_narrow( data->_smeshObject );
1978     if ( !submesh->_is_nil() ) // -------------- Sub mesh ---------------------
1979     {
1980       int oldID = submesh->GetId();
1981       if ( !_mapSubMeshIor.count( oldID ))
1982         continue;
1983       TopoDS_Shape oldShape = _mapSubMesh[oldID]->GetSubShape();
1984
1985       // update hypotheses
1986       list <const SMESHDS_Hypothesis * > hyps = _impl->GetHypothesisList(oldShape);
1987       list <const SMESHDS_Hypothesis * >::iterator hypIt;
1988       for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
1989       {
1990         _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
1991         _impl->AddHypothesis   ( newShape, (*hypIt)->GetID());
1992       }
1993       // care of submeshes
1994       SMESH_subMesh* newSubmesh = _impl->GetSubMesh( newShape );
1995       int newID = newSubmesh->GetId();
1996       if ( newID != oldID ) {
1997         _mapSubMesh   [ newID ] = newSubmesh;
1998         _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
1999         _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2000         _mapSubMesh.   erase(oldID);
2001         _mapSubMesh_i. erase(oldID);
2002         _mapSubMeshIor.erase(oldID);
2003         _mapSubMesh_i [ newID ]->changeLocalId( newID );
2004       }
2005       continue;
2006     }
2007
2008     SMESH::SMESH_GroupOnGeom_var smeshGroup =
2009       SMESH::SMESH_GroupOnGeom::_narrow( data->_smeshObject );
2010     if ( !smeshGroup->_is_nil() ) // ------------ GROUP -----------------------
2011     {
2012       SMESH_GroupOnGeom_i* group_i = SMESH::DownCast<SMESH_GroupOnGeom_i*>( smeshGroup );
2013       if ( group_i ) {
2014         ::SMESH_Group* group = _impl->GetGroup( group_i->GetLocalID() );
2015         SMESHDS_GroupOnGeom* ds = static_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() );
2016         ds->SetShape( newShape );
2017       }
2018       continue;
2019     }
2020
2021     SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( data->_smeshObject );
2022     if ( !mesh->_is_nil() ) // -------------- MESH ----------------------------
2023     {
2024       // Remove groups and submeshes basing on removed sub-shapes
2025
2026       TopTools_MapOfShape newShapeMap;
2027       TopoDS_Iterator shapeIt( newShape );
2028       for ( ; shapeIt.More(); shapeIt.Next() )
2029         newShapeMap.Add( shapeIt.Value() );
2030
2031       SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
2032       for ( shapeIt.Initialize( meshDS->ShapeToMesh() ); shapeIt.More(); shapeIt.Next() )
2033       {
2034         if ( newShapeMap.Contains( shapeIt.Value() ))
2035           continue;
2036         TopTools_IndexedMapOfShape oldShapeMap;
2037         TopExp::MapShapes( shapeIt.Value(), oldShapeMap );
2038         for ( int i = 1; i <= oldShapeMap.Extent(); ++i )
2039         {
2040           const TopoDS_Shape& oldShape = oldShapeMap(i);
2041           int oldInd = meshDS->ShapeToIndex( oldShape );
2042           // -- submeshes --
2043           map<int, SMESH::SMESH_subMesh_ptr>::iterator i_smIor = _mapSubMeshIor.find( oldInd );
2044           if ( i_smIor != _mapSubMeshIor.end() ) {
2045             RemoveSubMesh( i_smIor->second ); // one submesh per shape index
2046           }
2047           // --- groups ---
2048           map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.begin();
2049           for ( ; i_grp != _mapGroups.end(); ++i_grp )
2050           {
2051             // check if a group bases on oldInd shape
2052             SMESHDS_GroupOnGeom* grpOnGeom = 0;
2053             if ( ::SMESH_Group* g = _impl->GetGroup( i_grp->first ))
2054               grpOnGeom = dynamic_cast<SMESHDS_GroupOnGeom*>( g->GetGroupDS() );
2055             if ( grpOnGeom && oldShape.IsSame( grpOnGeom->GetShape() ))
2056             { // remove
2057               RemoveGroup( i_grp->second ); // several groups can base on same shape
2058               i_grp = _mapGroups.begin(); // _mapGroups changed - restart iteration
2059             }
2060           }
2061         }
2062       }
2063       // Reassign hypotheses and update groups after setting the new shape to mesh
2064
2065       // collect anassigned hypotheses
2066       typedef list< pair< TIndexedShape, list<const SMESHDS_Hypothesis*> > > TShapeHypList;
2067       list <const SMESHDS_Hypothesis * >::const_iterator hypIt;
2068       TShapeHypList assignedHyps;
2069       for ( int i = 1; i <= meshDS->MaxShapeIndex(); ++i )
2070       {
2071         const TopoDS_Shape& oldShape = meshDS->IndexToShape(i);
2072         list<const SMESHDS_Hypothesis*> hyps = meshDS->GetHypothesis( oldShape );// copy
2073         if ( !hyps.empty() ) {
2074           assignedHyps.push_back( make_pair( TIndexedShape(i,oldShape), hyps ));
2075           for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2076             _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
2077         }
2078       }
2079       // collect shapes supporting groups
2080       typedef list < pair< TIndexedShape, SMDSAbs_ElementType > > TShapeTypeList;
2081       TShapeTypeList groupData;
2082       const set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
2083       set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2084       for ( ; grIt != groups.end(); ++grIt )
2085       {
2086         if ( SMESHDS_GroupOnGeom* gog = dynamic_cast<SMESHDS_GroupOnGeom*>( *grIt ))
2087           groupData.push_back
2088             ( make_pair( TIndexedShape( gog->GetID(),gog->GetShape()), gog->GetType()));
2089       }
2090       // set new shape to mesh -> DS of submeshes and geom groups is deleted
2091       _impl->ShapeToMesh( newShape );
2092       
2093       // reassign hypotheses
2094       TShapeHypList::iterator indS_hyps = assignedHyps.begin();
2095       for ( ; indS_hyps != assignedHyps.end(); ++indS_hyps )
2096       {
2097         TIndexedShape&                   geom = indS_hyps->first;
2098         list<const SMESHDS_Hypothesis*>& hyps = indS_hyps->second;
2099         int oldID = geom._index;
2100         int newID = meshDS->ShapeToIndex( geom._shape );
2101         if ( oldID == 1 ) { // main shape
2102           newID = 1;
2103           geom._shape = newShape;
2104         }
2105         if ( !newID )
2106           continue;
2107         for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2108           _impl->AddHypothesis( geom._shape, (*hypIt)->GetID());
2109         // care of submeshes
2110         SMESH_subMesh* newSubmesh = _impl->GetSubMesh( geom._shape );
2111         if ( newID != oldID ) {
2112           _mapSubMesh   [ newID ] = newSubmesh;
2113           _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2114           _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2115           _mapSubMesh.   erase(oldID);
2116           _mapSubMesh_i. erase(oldID);
2117           _mapSubMeshIor.erase(oldID);
2118           _mapSubMesh_i [ newID ]->changeLocalId( newID );
2119         }
2120       }
2121       // recreate groups
2122       TShapeTypeList::iterator geomType = groupData.begin();
2123       for ( ; geomType != groupData.end(); ++geomType )
2124       {
2125         const TIndexedShape& geom = geomType->first;
2126         int oldID = geom._index;
2127         if ( _mapGroups.find( oldID ) == _mapGroups.end() )
2128           continue;
2129         // get group name
2130         SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( study,_mapGroups[oldID] );
2131         CORBA::String_var      name    = groupSO->GetName();
2132         // update
2133         SMESH_GroupBase_i*  group_i    = SMESH::DownCast<SMESH_GroupBase_i*>(_mapGroups[oldID] );
2134         int newID;
2135         if ( group_i && _impl->AddGroup( geomType->second, name.in(), newID, geom._shape ))
2136           group_i->changeLocalId( newID );
2137       }
2138
2139       break; // everything has been updated
2140
2141     } // update mesh
2142   } // loop on group data
2143
2144   // Update icons
2145
2146   CORBA::Long newNbEntities = NbNodes() + NbElements();
2147   list< SALOMEDS::SObject_wrap > soToUpdateIcons;
2148   if ( newNbEntities != nbEntities )
2149   {
2150     // Add all SObjects with icons to soToUpdateIcons
2151     soToUpdateIcons.push_back( _gen_i->ObjectToSObject( study, _this() )); // mesh
2152
2153     for (map<int, SMESH::SMESH_subMesh_ptr>::iterator i_sm = _mapSubMeshIor.begin();
2154          i_sm != _mapSubMeshIor.end(); ++i_sm ) // submeshes
2155       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( study, i_sm->second ));
2156
2157     for ( map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
2158           i_gr != _mapGroups.end(); ++i_gr ) // groups
2159       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( study, i_gr->second ));
2160   }
2161
2162   list< SALOMEDS::SObject_wrap >::iterator so = soToUpdateIcons.begin();
2163   for ( ; so != soToUpdateIcons.end(); ++so )
2164     _gen_i->SetPixMap( *so, "ICON_SMESH_TREE_MESH_WARN" );
2165 }
2166
2167 //=============================================================================
2168 /*!
2169  * \brief Create standalone group from a group on geometry or filter
2170  */
2171 //=============================================================================
2172
2173 SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupBase_ptr theGroup )
2174   throw (SALOME::SALOME_Exception)
2175 {
2176   SMESH::SMESH_Group_var aGroup;
2177
2178   SMESH_TRY;
2179
2180   if ( _preMeshInfo )
2181     _preMeshInfo->FullLoadFromFile();
2182
2183   if ( theGroup->_is_nil() )
2184     return aGroup._retn();
2185
2186   SMESH_GroupBase_i* aGroupToRem = SMESH::DownCast<SMESH_GroupBase_i*>( theGroup );
2187   if ( !aGroupToRem )
2188     return aGroup._retn();
2189
2190   const bool isOnFilter = ( SMESH::DownCast< SMESH_GroupOnFilter_i* > ( theGroup ));
2191
2192   const int anId = aGroupToRem->GetLocalID();
2193   if ( !_impl->ConvertToStandalone( anId ) )
2194     return aGroup._retn();
2195   removeGeomGroupData( theGroup );
2196
2197   SMESH_GroupBase_i* aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
2198
2199   // remove old instance of group from own map
2200   { SMESH::SMESH_GroupBase_var var( _mapGroups[anId] ); } // decref CORBA object
2201   _mapGroups.erase( anId );
2202
2203   SALOMEDS::StudyBuilder_var builder;
2204   SALOMEDS::SObject_wrap     aGroupSO;
2205   SALOMEDS::Study_var        aStudy = _gen_i->GetCurrentStudy();
2206   if ( !aStudy->_is_nil() ) {
2207     builder  = aStudy->NewBuilder();
2208     aGroupSO = _gen_i->ObjectToSObject( aStudy, theGroup );
2209     if ( !aGroupSO->_is_nil() )
2210     {
2211       // remove reference to geometry
2212       SALOMEDS::ChildIterator_wrap chItr = aStudy->NewChildIterator(aGroupSO);
2213       for ( ; chItr->More(); chItr->Next() )
2214         // Remove group's child SObject
2215         builder->RemoveObject( chItr->Value() );
2216
2217       // Update Python script
2218       TPythonDump() << aGroupSO << " = " << SMESH::SMESH_Mesh_var(_this())
2219                     << ".ConvertToStandalone( " << aGroupSO << " )";
2220
2221       // change icon of Group on Filter
2222       if ( isOnFilter )
2223       {
2224         SMESH::array_of_ElementType_var elemTypes = aGroupImpl->GetTypes();
2225         const int isEmpty = ( elemTypes->length() == 0 );
2226         if ( !isEmpty )
2227         {
2228           SALOMEDS::GenericAttribute_wrap anAttr =
2229             builder->FindOrCreateAttribute( aGroupSO, "AttributePixMap" );
2230           SALOMEDS::AttributePixMap_wrap pm = anAttr;
2231           pm->SetPixMap( "ICON_SMESH_TREE_GROUP" );
2232         }
2233       }
2234     }
2235   }
2236
2237   // remember new group in own map
2238   aGroup = SMESH::SMESH_Group::_narrow( aGroupImpl->_this() );
2239   _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
2240
2241   // register CORBA object for persistence
2242   _gen_i->RegisterObject( aGroup );
2243
2244   CORBA::String_var ior = _gen_i->GetORB()->object_to_string( aGroup );
2245   builder->SetIOR( aGroupSO, ior.in() ); //  == aGroup->Register();
2246   //aGroup->Register();
2247   aGroupToRem->UnRegister();
2248
2249   SMESH_CATCH( SMESH::throwCorbaException );
2250
2251   return aGroup._retn();
2252 }
2253
2254 //=============================================================================
2255 /*!
2256  *
2257  */
2258 //=============================================================================
2259
2260 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::createSubMesh( GEOM::GEOM_Object_ptr theSubShapeObject )
2261 {
2262   if(MYDEBUG) MESSAGE( "createSubMesh" );
2263   TopoDS_Shape  myLocSubShape = _gen_i->GeomObjectToShape(theSubShapeObject);
2264   ::SMESH_subMesh * mySubMesh = _impl->GetSubMesh(myLocSubShape);
2265   const int         subMeshId = mySubMesh->GetId();
2266
2267   SMESH_subMesh_i * subMeshServant = new SMESH_subMesh_i(myPOA, _gen_i, this, subMeshId);
2268   SMESH::SMESH_subMesh_var subMesh = subMeshServant->_this();
2269
2270   _mapSubMesh   [subMeshId] = mySubMesh;
2271   _mapSubMesh_i [subMeshId] = subMeshServant;
2272   _mapSubMeshIor[subMeshId] = SMESH::SMESH_subMesh::_duplicate( subMesh );
2273
2274   subMeshServant->Register();
2275
2276   // register CORBA object for persistence
2277   int nextId = _gen_i->RegisterObject( subMesh );
2278   if(MYDEBUG) { MESSAGE( "Add submesh to map with id = "<< nextId); }
2279   else        { nextId = 0; } // avoid "unused variable" warning
2280
2281   // to track changes of GEOM groups
2282   addGeomGroupData( theSubShapeObject, subMesh );
2283
2284   return subMesh._retn();
2285 }
2286
2287 //=======================================================================
2288 //function : getSubMesh
2289 //purpose  :
2290 //=======================================================================
2291
2292 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::getSubMesh(int shapeID)
2293 {
2294   map<int, SMESH::SMESH_subMesh_ptr>::iterator it = _mapSubMeshIor.find( shapeID );
2295   if ( it == _mapSubMeshIor.end() )
2296     return SMESH::SMESH_subMesh::_nil();
2297
2298   return SMESH::SMESH_subMesh::_duplicate( (*it).second );
2299 }
2300
2301 //=============================================================================
2302 /*!
2303  *
2304  */
2305 //=============================================================================
2306
2307 bool SMESH_Mesh_i::removeSubMesh (SMESH::SMESH_subMesh_ptr theSubMesh,
2308                                   GEOM::GEOM_Object_ptr    theSubShapeObject )
2309 {
2310   bool isHypChanged = false;
2311   if ( theSubMesh->_is_nil() /*|| theSubShapeObject->_is_nil()*/ )
2312     return isHypChanged;
2313
2314   const int subMeshId = theSubMesh->GetId();
2315
2316   if ( theSubShapeObject->_is_nil() )  // not published shape (IPAL13617)
2317   {
2318     if ( _mapSubMesh.find( subMeshId ) != _mapSubMesh.end())
2319     {
2320       TopoDS_Shape S = _mapSubMesh[ subMeshId ]->GetSubShape();
2321       if ( !S.IsNull() )
2322       {
2323         list<const SMESHDS_Hypothesis*> hyps = _impl->GetHypothesisList( S );
2324         isHypChanged = !hyps.empty();
2325         list<const SMESHDS_Hypothesis*>::const_iterator hyp = hyps.begin();
2326         for ( ; hyp != hyps.end(); ++hyp )
2327           _impl->RemoveHypothesis(S, (*hyp)->GetID());
2328       }
2329     }
2330   }
2331   else
2332   {
2333     try {
2334       SMESH::ListOfHypothesis_var aHypList = GetHypothesisList( theSubShapeObject );
2335       isHypChanged = ( aHypList->length() > 0 );
2336       for ( int i = 0, n = aHypList->length(); i < n; i++ ) {
2337         removeHypothesis( theSubShapeObject, aHypList[i] );
2338       }
2339     }
2340     catch( const SALOME::SALOME_Exception& ) {
2341       INFOS("SMESH_Mesh_i::removeSubMesh(): exception caught!");
2342     }
2343     removeGeomGroupData( theSubShapeObject );
2344   }
2345
2346   // remove a servant
2347   std::map<int, SMESH_subMesh_i*>::iterator id_smi = _mapSubMesh_i.find( subMeshId );
2348   if ( id_smi != _mapSubMesh_i.end() )
2349     id_smi->second->UnRegister();
2350
2351   // remove a CORBA object
2352   std::map<int, SMESH::SMESH_subMesh_ptr>::iterator id_smptr = _mapSubMeshIor.find( subMeshId );
2353   if ( id_smptr != _mapSubMeshIor.end() )
2354     SMESH::SMESH_subMesh_var( id_smptr->second );
2355
2356   _mapSubMesh.erase(subMeshId);
2357   _mapSubMesh_i.erase(subMeshId);
2358   _mapSubMeshIor.erase(subMeshId);
2359
2360   return isHypChanged;
2361 }
2362
2363 //=============================================================================
2364 /*!
2365  *
2366  */
2367 //=============================================================================
2368
2369 SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType        theElemType,
2370                                                       const char*               theName,
2371                                                       const TopoDS_Shape&       theShape,
2372                                                       const SMESH_PredicatePtr& thePredicate )
2373 {
2374   std::string newName;
2375   if ( !theName || strlen( theName ) == 0 )
2376   {
2377     std::set< std::string > presentNames;
2378     std::map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator i_gr = _mapGroups.begin();
2379     for ( ; i_gr != _mapGroups.end(); ++i_gr )
2380     {
2381       CORBA::String_var name = i_gr->second->GetName();
2382       presentNames.insert( name.in() );
2383     }
2384     do {
2385       newName = "noname_Group_" + SMESH_Comment( presentNames.size() + 1 );
2386     } while ( !presentNames.insert( newName ).second );
2387     theName = newName.c_str();
2388   }
2389   int anId;
2390   SMESH::SMESH_GroupBase_var aGroup;
2391   if ( _impl->AddGroup( (SMDSAbs_ElementType)theElemType, theName, anId, theShape, thePredicate ))
2392   {
2393     SMESH_GroupBase_i* aGroupImpl;
2394     if ( !theShape.IsNull() )
2395       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
2396     else if ( thePredicate )
2397       aGroupImpl = new SMESH_GroupOnFilter_i( SMESH_Gen_i::GetPOA(), this, anId );
2398     else
2399       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
2400
2401     aGroup = aGroupImpl->_this();
2402     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
2403     aGroupImpl->Register();
2404
2405     // register CORBA object for persistence
2406     int nextId = _gen_i->RegisterObject( aGroup );
2407     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
2408     else        { nextId = 0; } // avoid "unused variable" warning in release mode
2409
2410     // to track changes of GEOM groups
2411     if ( !theShape.IsNull() ) {
2412       GEOM::GEOM_Object_var geom = _gen_i->ShapeToGeomObject( theShape );
2413       addGeomGroupData( geom, aGroup );
2414     }
2415   }
2416   return aGroup._retn();
2417 }
2418
2419 //=============================================================================
2420 /*!
2421  * SMESH_Mesh_i::removeGroup
2422  *
2423  * Should be called by ~SMESH_Group_i()
2424  */
2425 //=============================================================================
2426
2427 void SMESH_Mesh_i::removeGroup( const int theId )
2428 {
2429   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::removeGroup()" );
2430   if ( _mapGroups.find( theId ) != _mapGroups.end() ) {
2431     SMESH::SMESH_GroupBase_var group = _mapGroups[theId];
2432     _mapGroups.erase( theId );
2433     removeGeomGroupData( group );
2434     if ( !_impl->RemoveGroup( theId ))
2435     {
2436       // it seems to be a call up from _impl caused by hyp modification (issue 0020918)
2437       RemoveGroup( group );
2438     }
2439     group->UnRegister();
2440   }
2441 }
2442
2443 //=============================================================================
2444 /*!
2445  *
2446  */
2447 //=============================================================================
2448
2449 SMESH::log_array * SMESH_Mesh_i::GetLog(CORBA::Boolean clearAfterGet)
2450   throw(SALOME::SALOME_Exception)
2451 {
2452   SMESH::log_array_var aLog;
2453
2454   SMESH_TRY;
2455   if ( _preMeshInfo )
2456     _preMeshInfo->FullLoadFromFile();
2457
2458   list < SMESHDS_Command * >logDS = _impl->GetLog();
2459   aLog = new SMESH::log_array;
2460   int indexLog = 0;
2461   int lg = logDS.size();
2462   SCRUTE(lg);
2463   aLog->length(lg);
2464   list < SMESHDS_Command * >::iterator its = logDS.begin();
2465   while(its != logDS.end()){
2466     SMESHDS_Command *com = *its;
2467     int comType = com->GetType();
2468     //SCRUTE(comType);
2469     int lgcom = com->GetNumber();
2470     //SCRUTE(lgcom);
2471     const list < int >&intList = com->GetIndexes();
2472     int inum = intList.size();
2473     //SCRUTE(inum);
2474     list < int >::const_iterator ii = intList.begin();
2475     const list < double >&coordList = com->GetCoords();
2476     int rnum = coordList.size();
2477     //SCRUTE(rnum);
2478     list < double >::const_iterator ir = coordList.begin();
2479     aLog[indexLog].commandType = comType;
2480     aLog[indexLog].number = lgcom;
2481     aLog[indexLog].coords.length(rnum);
2482     aLog[indexLog].indexes.length(inum);
2483     for(int i = 0; i < rnum; i++){
2484       aLog[indexLog].coords[i] = *ir;
2485       //MESSAGE(" "<<i<<" "<<ir.Value());
2486       ir++;
2487     }
2488     for(int i = 0; i < inum; i++){
2489       aLog[indexLog].indexes[i] = *ii;
2490       //MESSAGE(" "<<i<<" "<<ii.Value());
2491       ii++;
2492     }
2493     indexLog++;
2494     its++;
2495   }
2496   if(clearAfterGet)
2497     _impl->ClearLog();
2498
2499   SMESH_CATCH( SMESH::throwCorbaException );
2500
2501   return aLog._retn();
2502 }
2503
2504
2505 //=============================================================================
2506 /*!
2507  *
2508  */
2509 //=============================================================================
2510
2511 void SMESH_Mesh_i::ClearLog() throw(SALOME::SALOME_Exception)
2512 {
2513   SMESH_TRY;
2514   _impl->ClearLog();
2515   SMESH_CATCH( SMESH::throwCorbaException );
2516 }
2517
2518 //=============================================================================
2519 /*!
2520  *
2521  */
2522 //=============================================================================
2523
2524 CORBA::Long SMESH_Mesh_i::GetId()throw(SALOME::SALOME_Exception)
2525 {
2526   return _id;
2527 }
2528
2529 //=============================================================================
2530 /*!
2531  *
2532  */
2533 //=============================================================================
2534
2535 CORBA::Long SMESH_Mesh_i::GetStudyId()throw(SALOME::SALOME_Exception)
2536 {
2537   return _studyId;
2538 }
2539
2540 //=============================================================================
2541 namespace
2542 {
2543   //!< implementation of struct used to call methods of SMESH_Mesh_i from SMESH_Mesh
2544   // issue 0020918: groups removal is caused by hyp modification
2545   // issue 0021208: to forget not loaded mesh data at hyp modification
2546   struct TCallUp_i : public SMESH_Mesh::TCallUp
2547   {
2548     SMESH_Mesh_i* _mesh;
2549     TCallUp_i(SMESH_Mesh_i* mesh):_mesh(mesh) {}
2550     virtual void RemoveGroup (const int theGroupID) { _mesh->removeGroup( theGroupID ); }
2551     virtual void HypothesisModified ()              { _mesh->onHypothesisModified(); }
2552     virtual void Load ()                            { _mesh->Load(); }
2553   };
2554 }
2555
2556 //================================================================================
2557 /*!
2558  * \brief callback from _impl to forget not loaded mesh data (issue 0021208)
2559  */
2560 //================================================================================
2561
2562 void SMESH_Mesh_i::onHypothesisModified()
2563 {
2564   if ( _preMeshInfo )
2565     _preMeshInfo->ForgetOrLoad();
2566 }
2567
2568 //=============================================================================
2569 /*!
2570  *
2571  */
2572 //=============================================================================
2573
2574 void SMESH_Mesh_i::SetImpl(::SMESH_Mesh * impl)
2575 {
2576   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::SetImpl");
2577   _impl = impl;
2578   if ( _impl )
2579     _impl->SetCallUp( new TCallUp_i(this));
2580 }
2581
2582 //=============================================================================
2583 /*!
2584  *
2585  */
2586 //=============================================================================
2587
2588 ::SMESH_Mesh & SMESH_Mesh_i::GetImpl()
2589 {
2590   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::GetImpl()");
2591   return *_impl;
2592 }
2593
2594 //=============================================================================
2595 /*!
2596  * Return mesh editor
2597  */
2598 //=============================================================================
2599
2600 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditor()
2601   throw (SALOME::SALOME_Exception)
2602 {
2603   SMESH::SMESH_MeshEditor_var aMeshEdVar;
2604
2605   SMESH_TRY;
2606   if ( _preMeshInfo )
2607     _preMeshInfo->FullLoadFromFile();
2608
2609   // Create MeshEditor
2610   if ( !_editor )
2611     _editor = new SMESH_MeshEditor_i( this, false );
2612   aMeshEdVar = _editor->_this();
2613
2614   // Update Python script
2615   TPythonDump() << _editor << " = "
2616                 << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshEditor()";
2617
2618   SMESH_CATCH( SMESH::throwCorbaException );
2619
2620   return aMeshEdVar._retn();
2621 }
2622
2623 //=============================================================================
2624 /*!
2625  * Return mesh edition previewer
2626  */
2627 //=============================================================================
2628
2629 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditPreviewer()
2630   throw (SALOME::SALOME_Exception)
2631 {
2632   SMESH::SMESH_MeshEditor_var aMeshEdVar;
2633
2634   SMESH_TRY;
2635   if ( _preMeshInfo )
2636     _preMeshInfo->FullLoadFromFile();
2637
2638   if ( !_previewEditor )
2639     _previewEditor = new SMESH_MeshEditor_i( this, true );
2640   aMeshEdVar = _previewEditor->_this();
2641
2642   SMESH_CATCH( SMESH::throwCorbaException );
2643
2644   return aMeshEdVar._retn();
2645 }
2646
2647 //================================================================================
2648 /*!
2649  * \brief Return true if the mesh has been edited since a last total re-compute
2650  *        and those modifications may prevent successful partial re-compute
2651  */
2652 //================================================================================
2653
2654 CORBA::Boolean SMESH_Mesh_i::HasModificationsToDiscard() throw(SALOME::SALOME_Exception)
2655 {
2656   Unexpect aCatch(SALOME_SalomeException);
2657   return _impl->HasModificationsToDiscard();
2658 }
2659
2660 //================================================================================
2661 /*!
2662  * \brief Returns a random unique color
2663  */
2664 //================================================================================
2665
2666 static SALOMEDS::Color getUniqueColor( const std::list<SALOMEDS::Color>& theReservedColors )
2667 {
2668   const int MAX_ATTEMPTS = 100;
2669   int cnt = 0;
2670   double tolerance = 0.5;
2671   SALOMEDS::Color col;
2672
2673   bool ok = false;
2674   while ( !ok ) {
2675     // generate random color
2676     double red    = (double)rand() / RAND_MAX;
2677     double green  = (double)rand() / RAND_MAX;
2678     double blue   = (double)rand() / RAND_MAX;
2679     // check existence in the list of the existing colors
2680     bool matched = false;
2681     std::list<SALOMEDS::Color>::const_iterator it;
2682     for ( it = theReservedColors.begin(); it != theReservedColors.end() && !matched; ++it ) {
2683       SALOMEDS::Color color = *it;
2684       double tol = fabs( color.R - red ) + fabs( color.G - green ) + fabs( color.B  - blue  );
2685       matched = tol < tolerance;
2686     }
2687     if ( (cnt+1) % 20 == 0 ) tolerance = tolerance/2;
2688     ok = ( ++cnt == MAX_ATTEMPTS ) || !matched;
2689     col.R = red;
2690     col.G = green;
2691     col.B = blue;
2692   }
2693   return col;
2694 }
2695
2696 //=============================================================================
2697 /*!
2698  * Sets auto-color mode. If it is on, groups get unique random colors
2699  */
2700 //=============================================================================
2701
2702 void SMESH_Mesh_i::SetAutoColor(CORBA::Boolean theAutoColor) throw(SALOME::SALOME_Exception)
2703 {
2704   Unexpect aCatch(SALOME_SalomeException);
2705   _impl->SetAutoColor(theAutoColor);
2706
2707   TPythonDump pyDump; // not to dump group->SetColor() from below code
2708   pyDump << SMESH::SMESH_Mesh_var(_this()) <<".SetAutoColor( "<<theAutoColor<<" )";
2709
2710   std::list<SALOMEDS::Color> aReservedColors;
2711   map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.begin();
2712   for ( ; it != _mapGroups.end(); it++ ) {
2713     if ( CORBA::is_nil( it->second )) continue;
2714     SALOMEDS::Color aColor = getUniqueColor( aReservedColors );
2715     it->second->SetColor( aColor );
2716     aReservedColors.push_back( aColor );
2717   }
2718 }
2719
2720 //=============================================================================
2721 /*!
2722  * Returns true if auto-color mode is on
2723  */
2724 //=============================================================================
2725
2726 CORBA::Boolean SMESH_Mesh_i::GetAutoColor() throw(SALOME::SALOME_Exception)
2727 {
2728   Unexpect aCatch(SALOME_SalomeException);
2729   return _impl->GetAutoColor();
2730 }
2731
2732 //=============================================================================
2733 /*!
2734  *  Checks if there are groups with equal names
2735  */
2736 //=============================================================================
2737
2738 CORBA::Boolean SMESH_Mesh_i::HasDuplicatedGroupNamesMED()
2739 {
2740   return _impl->HasDuplicatedGroupNamesMED();
2741 }
2742
2743 //================================================================================
2744 /*!
2745  * \brief Care of a file before exporting mesh into it
2746  */
2747 //================================================================================
2748
2749 void SMESH_Mesh_i::PrepareForWriting (const char* file, bool overwrite)
2750 {
2751   TCollection_AsciiString aFullName ((char*)file);
2752   OSD_Path aPath (aFullName);
2753   OSD_File aFile (aPath);
2754   if (aFile.Exists()) {
2755     // existing filesystem node
2756     if (aFile.KindOfFile() == OSD_FILE) {
2757       if (aFile.IsWriteable()) {
2758         if (overwrite) {
2759           aFile.Reset();
2760           aFile.Remove();
2761         }
2762         if (aFile.Failed()) {
2763           TCollection_AsciiString msg ("File ");
2764           msg += aFullName + " cannot be replaced.";
2765           THROW_SALOME_CORBA_EXCEPTION(msg.ToCString(), SALOME::BAD_PARAM);
2766         }
2767       } else {
2768         TCollection_AsciiString msg ("File ");
2769         msg += aFullName + " cannot be overwritten.";
2770         THROW_SALOME_CORBA_EXCEPTION(msg.ToCString(), SALOME::BAD_PARAM);
2771       }
2772     } else {
2773       TCollection_AsciiString msg ("Location ");
2774       msg += aFullName + " is not a file.";
2775       THROW_SALOME_CORBA_EXCEPTION(msg.ToCString(), SALOME::BAD_PARAM);
2776     }
2777   } else {
2778     // nonexisting file; check if it can be created
2779     aFile.Reset();
2780     aFile.Build(OSD_WriteOnly, OSD_Protection());
2781     if (aFile.Failed()) {
2782       TCollection_AsciiString msg ("You cannot create the file ");
2783       msg += aFullName + ". Check the directory existance and access rights.";
2784       THROW_SALOME_CORBA_EXCEPTION(msg.ToCString(), SALOME::BAD_PARAM);
2785     } else {
2786       aFile.Close();
2787       aFile.Remove();
2788     }
2789   }
2790 }
2791
2792 //================================================================================
2793 /*!
2794  * \brief Prepares a file for export and pass names of mesh groups from study to mesh DS
2795  *  \param file - file name
2796  *  \param overwrite - to erase the file or not
2797  *  \retval string - mesh name
2798  */
2799 //================================================================================
2800
2801 string SMESH_Mesh_i::prepareMeshNameAndGroups(const char*    file,
2802                                               CORBA::Boolean overwrite)
2803 {
2804   // Perform Export
2805   PrepareForWriting(file, overwrite);
2806   string aMeshName = "Mesh";
2807   SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy();
2808   if ( !aStudy->_is_nil() ) {
2809     SALOMEDS::SObject_wrap aMeshSO = _gen_i->ObjectToSObject( aStudy, _this() );
2810     if ( !aMeshSO->_is_nil() ) {
2811       CORBA::String_var name = aMeshSO->GetName();
2812       aMeshName = name;
2813       // asv : 27.10.04 : fix of 6903: check for StudyLocked before adding attributes
2814       if ( !aStudy->GetProperties()->IsLocked() )
2815       {
2816         SALOMEDS::GenericAttribute_wrap anAttr;
2817         SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder();
2818         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeExternalFileDef");
2819         SALOMEDS::AttributeExternalFileDef_wrap aFileName = anAttr;
2820         ASSERT(!aFileName->_is_nil());
2821         aFileName->SetValue(file);
2822         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeFileType");
2823         SALOMEDS::AttributeFileType_wrap aFileType = anAttr;
2824         ASSERT(!aFileType->_is_nil());
2825         aFileType->SetValue("FICHIERMED");
2826       }
2827     }
2828   }
2829   // Update Python script
2830   // set name of mesh before export
2831   TPythonDump() << _gen_i << ".SetName("
2832                 << SMESH::SMESH_Mesh_var(_this()) << ", '" << aMeshName.c_str() << "')";
2833
2834   // check names of groups
2835   checkGroupNames();
2836
2837   return aMeshName;
2838 }
2839
2840 //================================================================================
2841 /*!
2842  * \brief Export to med file
2843  */
2844 //================================================================================
2845
2846 void SMESH_Mesh_i::ExportToMEDX (const char*        file,
2847                                  CORBA::Boolean     auto_groups,
2848                                  SMESH::MED_VERSION theVersion,
2849                                  CORBA::Boolean     overwrite,
2850                                  CORBA::Boolean     autoDimension)
2851   throw(SALOME::SALOME_Exception)
2852 {
2853   SMESH_TRY;
2854   if ( _preMeshInfo )
2855     _preMeshInfo->FullLoadFromFile();
2856
2857   string aMeshName = prepareMeshNameAndGroups(file, overwrite);
2858   _impl->ExportMED( file, aMeshName.c_str(), auto_groups, theVersion, 0, autoDimension );
2859
2860   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportToMEDX( r'"
2861                 << file << "', " << auto_groups << ", "
2862                 << theVersion << ", " << overwrite << ", "
2863                 << autoDimension << " )";
2864
2865   SMESH_CATCH( SMESH::throwCorbaException );
2866 }
2867
2868 //================================================================================
2869 /*!
2870  * \brief Export a mesh to a med file
2871  */
2872 //================================================================================
2873
2874 void SMESH_Mesh_i::ExportToMED (const char*        file,
2875                                 CORBA::Boolean     auto_groups,
2876                                 SMESH::MED_VERSION theVersion)
2877   throw(SALOME::SALOME_Exception)
2878 {
2879   ExportToMEDX(file,auto_groups,theVersion,true);
2880 }
2881
2882 //================================================================================
2883 /*!
2884  * \brief Export a mesh to a med file
2885  */
2886 //================================================================================
2887
2888 void SMESH_Mesh_i::ExportMED (const char* file,
2889                               CORBA::Boolean auto_groups)
2890   throw(SALOME::SALOME_Exception)
2891 {
2892   ExportToMEDX(file,auto_groups,SMESH::MED_V2_2,true);
2893 }
2894
2895 //================================================================================
2896 /*!
2897  * \brief Export a mesh to a SAUV file
2898  */
2899 //================================================================================
2900
2901 void SMESH_Mesh_i::ExportSAUV (const char* file,
2902                                CORBA::Boolean auto_groups)
2903   throw(SALOME::SALOME_Exception)
2904 {
2905   Unexpect aCatch(SALOME_SalomeException);
2906   if ( _preMeshInfo )
2907     _preMeshInfo->FullLoadFromFile();
2908
2909   string aMeshName = prepareMeshNameAndGroups(file, true);
2910   TPythonDump() << SMESH::SMESH_Mesh_var( _this())
2911                 << ".ExportSAUV( r'" << file << "', " << auto_groups << " )";
2912   _impl->ExportSAUV(file, aMeshName.c_str(), auto_groups);
2913 }
2914
2915
2916 //================================================================================
2917 /*!
2918  * \brief Export a mesh to a DAT file
2919  */
2920 //================================================================================
2921
2922 void SMESH_Mesh_i::ExportDAT (const char *file)
2923   throw(SALOME::SALOME_Exception)
2924 {
2925   Unexpect aCatch(SALOME_SalomeException);
2926   if ( _preMeshInfo )
2927     _preMeshInfo->FullLoadFromFile();
2928
2929   // Update Python script
2930   // check names of groups
2931   checkGroupNames();
2932   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportDAT( r'" << file << "' )";
2933
2934   // Perform Export
2935   PrepareForWriting(file);
2936   _impl->ExportDAT(file);
2937 }
2938
2939 //================================================================================
2940 /*!
2941  * \brief Export a mesh to an UNV file
2942  */
2943 //================================================================================
2944
2945 void SMESH_Mesh_i::ExportUNV (const char *file)
2946   throw(SALOME::SALOME_Exception)
2947 {
2948   Unexpect aCatch(SALOME_SalomeException);
2949   if ( _preMeshInfo )
2950     _preMeshInfo->FullLoadFromFile();
2951
2952   // Update Python script
2953   // check names of groups
2954   checkGroupNames();
2955   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportUNV( r'" << file << "' )";
2956
2957   // Perform Export
2958   PrepareForWriting(file);
2959   _impl->ExportUNV(file);
2960 }
2961
2962 //================================================================================
2963 /*!
2964  * \brief Export a mesh to an STL file
2965  */
2966 //================================================================================
2967
2968 void SMESH_Mesh_i::ExportSTL (const char *file, const bool isascii)
2969   throw(SALOME::SALOME_Exception)
2970 {
2971   Unexpect aCatch(SALOME_SalomeException);
2972   if ( _preMeshInfo )
2973     _preMeshInfo->FullLoadFromFile();
2974
2975   // Update Python script
2976   // check names of groups
2977   checkGroupNames();
2978   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
2979                 << ".ExportSTL( r'" << file << "', " << isascii << " )";
2980
2981   // Perform Export
2982   PrepareForWriting(file);
2983   _impl->ExportSTL(file, isascii);
2984 }
2985
2986 //================================================================================
2987 /*!
2988  * \brief Export a part of mesh to a med file
2989  */
2990 //================================================================================
2991
2992 void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
2993                                    const char*               file,
2994                                    CORBA::Boolean            auto_groups,
2995                                    SMESH::MED_VERSION        version,
2996                                    CORBA::Boolean            overwrite,
2997                                    CORBA::Boolean            autoDimension,
2998                                    const GEOM::ListOfFields& fields,
2999                                    const char*               geomAssocFields)
3000   throw (SALOME::SALOME_Exception)
3001 {
3002   SMESH_TRY;
3003   if ( _preMeshInfo )
3004     _preMeshInfo->FullLoadFromFile();
3005
3006   // check fields
3007   bool have0dField = false;
3008   if ( fields.length() > 0 )
3009   {
3010     GEOM::GEOM_Object_var shapeToMesh = GetShapeToMesh();
3011     if ( shapeToMesh->_is_nil() )
3012       THROW_SALOME_CORBA_EXCEPTION( "No shape to mesh", SALOME::INTERNAL_ERROR );
3013
3014     for ( size_t i = 0; i < fields.length(); ++i )
3015     {
3016       if ( fields[i]->GetDataType() == GEOM::FDT_String )
3017         THROW_SALOME_CORBA_EXCEPTION
3018           ( "Export of string fields is not supported", SALOME::BAD_PARAM);
3019       GEOM::GEOM_Object_var fieldShape = fields[i]->GetShape();
3020       if ( fieldShape->_is_nil() )
3021         THROW_SALOME_CORBA_EXCEPTION( "Null shape under a field", SALOME::INTERNAL_ERROR );
3022       if ( !fieldShape->IsSame( shapeToMesh ) )
3023         THROW_SALOME_CORBA_EXCEPTION
3024           ( "Field defined not on shape", SALOME::BAD_PARAM);
3025       if ( fields[i]->GetDimension() == 0 )
3026         have0dField = true;
3027     }
3028     if ( geomAssocFields )
3029       for ( int i = 0; geomAssocFields[i]; ++i )
3030         switch ( geomAssocFields[i] ) {
3031         case 'v':case 'e':case 'f':case 's': break;
3032         case 'V':case 'E':case 'F':case 'S': break;
3033         default: THROW_SALOME_CORBA_EXCEPTION
3034             ( "geomAssocFields can include only [vefs] characters", SALOME::BAD_PARAM);
3035         }
3036   }
3037
3038   SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
3039
3040   // write mesh
3041
3042   string aMeshName = "Mesh";
3043   SMESHUtils::Deleter< SMESH_MeshPartDS > tmpDSDeleter(0);
3044   if ( CORBA::is_nil( meshPart ) ||
3045        SMESH::DownCast< SMESH_Mesh_i* >( meshPart ))
3046   {
3047     aMeshName = prepareMeshNameAndGroups(file, overwrite);
3048     _impl->ExportMED( file, aMeshName.c_str(), auto_groups,
3049                       version, 0, autoDimension, have0dField);
3050     meshDS = _impl->GetMeshDS();
3051   }
3052   else
3053   {
3054     if ( _preMeshInfo )
3055       _preMeshInfo->FullLoadFromFile();
3056
3057     PrepareForWriting(file, overwrite);
3058
3059     SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy();
3060     if ( !aStudy->_is_nil() ) {
3061       SALOMEDS::SObject_wrap SO = _gen_i->ObjectToSObject( aStudy, meshPart );
3062       if ( !SO->_is_nil() ) {
3063         CORBA::String_var name = SO->GetName();
3064         aMeshName = name;
3065       }
3066     }
3067     SMESH_MeshPartDS* partDS = new SMESH_MeshPartDS( meshPart );
3068     _impl->ExportMED( file, aMeshName.c_str(), auto_groups,
3069                       version, partDS, autoDimension, have0dField);
3070     meshDS = tmpDSDeleter._obj = partDS;
3071   }
3072
3073   // write fields
3074
3075   if ( _impl->HasShapeToMesh() )
3076   {
3077     DriverMED_W_Field fieldWriter;
3078     fieldWriter.SetFile( file );
3079     fieldWriter.SetMeshName( aMeshName );
3080     fieldWriter.AddODOnVertices( have0dField );
3081
3082     exportMEDFields( fieldWriter, meshDS, fields, geomAssocFields );
3083   }
3084
3085   // dump
3086   GEOM::ListOfGBO_var goList = new GEOM::ListOfGBO;
3087   goList->length( fields.length() );
3088   for ( size_t i = 0; i < fields.length(); ++i )
3089   {
3090     GEOM::GEOM_BaseObject_var gbo = GEOM::GEOM_BaseObject::_narrow( fields[i] );
3091     goList[i] = gbo;
3092   }
3093   TPythonDump() << _this() << ".ExportPartToMED( "
3094                 << meshPart << ", r'" << file << "', "
3095                 << auto_groups << ", " << version << ", " << overwrite << ", "
3096                 << autoDimension << ", " << goList
3097                 << ", '" << ( geomAssocFields ? geomAssocFields : "" ) << "'" << " )";
3098
3099   SMESH_CATCH( SMESH::throwCorbaException );
3100 }
3101
3102 //================================================================================
3103 /*!
3104  * Write GEOM fields to MED file
3105  */
3106 //================================================================================
3107
3108 void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
3109                                     SMESHDS_Mesh*             meshDS,
3110                                     const GEOM::ListOfFields& fields,
3111                                     const char*               geomAssocFields)
3112 {
3113 #define METH "SMESH_Mesh_i::exportMEDFields() "
3114
3115   if (( fields.length() < 1 ) &&
3116       ( !geomAssocFields || !geomAssocFields[0] ))
3117     return;
3118
3119   std::vector< double > dblVals( meshDS->MaxShapeIndex()+1 );
3120   std::vector< int >    intVals( meshDS->MaxShapeIndex()+1 );
3121   std::vector< int >    subIdsByDim[ 4 ];
3122   const double noneDblValue = 0.;
3123   const double noneIntValue = 0;
3124
3125   for ( size_t iF = 0; iF < fields.length(); ++iF )
3126   {
3127     // set field data
3128
3129     int dim = fields[ iF ]->GetDimension();
3130     SMDSAbs_ElementType elemType;
3131     TopAbs_ShapeEnum    shapeType;
3132     switch ( dim ) {
3133     case 0: elemType = SMDSAbs_0DElement; shapeType = TopAbs_VERTEX; break;
3134     case 1: elemType = SMDSAbs_Edge;      shapeType = TopAbs_EDGE;   break;
3135     case 2: elemType = SMDSAbs_Face;      shapeType = TopAbs_FACE;   break;
3136     case 3: elemType = SMDSAbs_Volume;    shapeType = TopAbs_SOLID;  break;
3137     default:
3138       continue; // skip fields on whole shape
3139     }
3140     GEOM::field_data_type dataType = fields[ iF ]->GetDataType();
3141     if ( dataType == GEOM::FDT_String )
3142       continue;
3143     GEOM::ListOfLong_var stepIDs = fields[ iF ]->GetSteps();
3144     if ( stepIDs->length() < 1 )
3145       continue;
3146     GEOM::string_array_var comps = fields[ iF ]->GetComponents();
3147     if ( comps->length() < 1 )
3148       continue;
3149     CORBA::String_var       name = fields[ iF ]->GetName();
3150
3151     if ( !fieldWriter.Set( meshDS,
3152                            name.in(),
3153                            elemType,
3154                            comps->length(),
3155                            ( dataType == GEOM::FDT_Int )))
3156       continue;
3157
3158     for ( size_t iC = 0; iC < comps->length(); ++iC )
3159       fieldWriter.SetCompName( iC, comps[ iC ].in() );
3160
3161     // find sub-shape IDs
3162
3163     std::vector< int >& subIds = subIdsByDim[ dim ];
3164     if ( subIds.empty() )
3165       for ( int id = 1; id <= meshDS->MaxShapeIndex(); ++id )
3166         if ( meshDS->IndexToShape( id ).ShapeType() == shapeType )
3167           subIds.push_back( id );
3168
3169     // write steps
3170
3171     SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
3172     if ( !elemIt )
3173       continue;
3174
3175     for ( size_t iS = 0; iS < stepIDs->length(); ++iS )
3176     {
3177       GEOM::GEOM_FieldStep_var step = fields[ iF ]->GetStep( stepIDs[ iS ]);
3178       if ( step->_is_nil() )
3179         continue;
3180
3181       CORBA::Long stamp = step->GetStamp();
3182       CORBA::Long id    = step->GetID();
3183       fieldWriter.SetDtIt( int( stamp ), int( id ));
3184
3185       // fill dblVals or intVals
3186       switch ( dataType )
3187       {
3188       case GEOM::FDT_Double:
3189       {
3190         GEOM::GEOM_DoubleFieldStep_var dblStep = GEOM::GEOM_DoubleFieldStep::_narrow( step );
3191         if ( dblStep->_is_nil() ) continue;
3192         GEOM::ListOfDouble_var vv = dblStep->GetValues();
3193         if ( vv->length() != subIds.size() )
3194           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
3195         for ( size_t i = 0; i < vv->length(); ++i )
3196           dblVals[ subIds[ i ]] = vv[ i ];
3197         break;
3198       }
3199       case GEOM::FDT_Int:
3200       {
3201         GEOM::GEOM_IntFieldStep_var intStep = GEOM::GEOM_IntFieldStep::_narrow( step );
3202         if ( intStep->_is_nil() ) continue;
3203         GEOM::ListOfLong_var vv = intStep->GetValues();
3204         if ( vv->length() != subIds.size() )
3205           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
3206         for ( size_t i = 0; i < vv->length(); ++i )
3207           intVals[ subIds[ i ]] = (int) vv[ i ];
3208         break;
3209       }
3210       case GEOM::FDT_Bool:
3211       {
3212         GEOM::GEOM_BoolFieldStep_var boolStep = GEOM::GEOM_BoolFieldStep::_narrow( step );
3213         if ( boolStep->_is_nil() ) continue;
3214         GEOM::short_array_var vv = boolStep->GetValues();
3215         if ( vv->length() != subIds.size() )
3216           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
3217         for ( size_t i = 0; i < vv->length(); ++i )
3218           intVals[ subIds[ i ]] = (int) vv[ i ];
3219         break;
3220       }
3221       default: continue;
3222       }
3223
3224       // pass values to fieldWriter
3225       elemIt = fieldWriter.GetOrderedElems();
3226       if ( dataType == GEOM::FDT_Double )
3227         while ( elemIt->more() )
3228         {
3229           const SMDS_MeshElement* e = elemIt->next();