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