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