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