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