Salome HOME
54416: Extrusion 3D algo is not applicable to a prismatic shape
[modules/smesh.git] / src / SMESH_I / SMESH_Mesh_i.cxx
1 // Copyright (C) 2007-2019  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   if ( aGroup->GetMeshServant() != this )
1108     THROW_SALOME_CORBA_EXCEPTION( "RemoveGroup(): group does not belong to this mesh",
1109                                   SALOME::BAD_PARAM );
1110
1111   SALOMEDS::SObject_wrap aGroupSO = _gen_i->ObjectToSObject( theGroup );
1112   if ( !aGroupSO->_is_nil() )
1113   {
1114     // Update Python script
1115     TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".RemoveGroup( " << aGroupSO << " )";
1116
1117     // Remove group's SObject
1118     SALOMEDS::StudyBuilder_var builder = SMESH_Gen_i::getStudyServant()->NewBuilder();
1119     builder->RemoveObjectWithChildren( aGroupSO );
1120   }
1121   aGroup->Modified(/*removed=*/true); // notify dependent Filter with FT_BelongToMeshGroup criterion
1122
1123   // Remove the group from SMESH data structures
1124   removeGroup( aGroup->GetLocalID() );
1125
1126   SMESH_CATCH( SMESH::throwCorbaException );
1127 }
1128
1129 //=============================================================================
1130 /*!
1131  *  Remove group with its contents
1132  */
1133 //=============================================================================
1134
1135 void SMESH_Mesh_i::RemoveGroupWithContents( SMESH::SMESH_GroupBase_ptr theGroup )
1136   throw (SALOME::SALOME_Exception)
1137 {
1138   SMESH_TRY;
1139   if ( _preMeshInfo )
1140     _preMeshInfo->FullLoadFromFile();
1141
1142   if ( theGroup->_is_nil() )
1143     return;
1144
1145   SMESH_GroupBase_i* groupImpl = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup );
1146   if ( !groupImpl || groupImpl->GetMeshServant() != this )
1147     THROW_SALOME_CORBA_EXCEPTION( "RemoveGroupWithContents(): group does not belong to this mesh",
1148                                   SALOME::BAD_PARAM);
1149
1150   vector<int> nodeIds; // to remove nodes becoming free
1151   bool isNodal = ( theGroup->GetType() == SMESH::NODE );
1152   if ( !isNodal && !theGroup->IsEmpty() )
1153   {
1154     CORBA::Long elemID = theGroup->GetID( 1 );
1155     int nbElemNodes = GetElemNbNodes( elemID );
1156     if ( nbElemNodes > 0 )
1157       nodeIds.reserve( theGroup->Size() * nbElemNodes );
1158   }
1159
1160   // Retrieve contents
1161   SMESH::SMESH_IDSource_var idSrc = SMESH::SMESH_IDSource::_narrow( theGroup );
1162   SMDS_ElemIteratorPtr     elemIt = GetElements( idSrc, theGroup->GetType() );
1163   SMDS_StdIterator< const SMDS_MeshElement*, SMDS_ElemIteratorPtr > elemBeg( elemIt ), elemEnd;
1164   std::vector< const SMDS_MeshElement* > elems( theGroup->Size() );
1165   elems.assign( elemBeg, elemEnd );
1166
1167   TPythonDump pyDump; // Suppress dump from RemoveGroup()
1168
1169   // Remove group
1170   RemoveGroup( theGroup );
1171
1172   // Remove contents
1173   for ( size_t i = 0; i < elems.size(); ++i )
1174   {
1175     // if ( !_impl->GetMeshDS()->Contains( elems[i] ))
1176     //   continue;
1177     if ( !isNodal )
1178     {
1179       for ( SMDS_ElemIteratorPtr nIt = elems[i]->nodesIterator(); nIt->more(); )
1180         nodeIds.push_back( nIt->next()->GetID() );
1181
1182       _impl->GetMeshDS()->RemoveFreeElement( elems[i], /*sm=*/0 );
1183     }
1184     else
1185     {
1186       _impl->GetMeshDS()->RemoveElement( elems[i] );
1187     }
1188   }
1189
1190   // Remove free nodes
1191   for ( size_t i = 0 ; i < nodeIds.size(); ++i )
1192     if ( const SMDS_MeshNode* n = _impl->GetMeshDS()->FindNode( nodeIds[i] ))
1193       if ( n->NbInverseElements() == 0 )
1194         _impl->GetMeshDS()->RemoveFreeNode( n, /*sm=*/0 );
1195
1196   // Update Python script (theGroup must be alive for this)
1197   pyDump << SMESH::SMESH_Mesh_var(_this())
1198          << ".RemoveGroupWithContents( " << theGroup << " )";
1199
1200   SMESH_CATCH( SMESH::throwCorbaException );
1201 }
1202
1203 //================================================================================
1204 /*!
1205  * \brief Get the list of groups existing in the mesh
1206  *  \retval SMESH::ListOfGroups * - list of groups
1207  */
1208 //================================================================================
1209
1210 SMESH::ListOfGroups * SMESH_Mesh_i::GetGroups() throw(SALOME::SALOME_Exception)
1211 {
1212   Unexpect aCatch(SALOME_SalomeException);
1213   if (MYDEBUG) MESSAGE("GetGroups");
1214
1215   SMESH::ListOfGroups_var aList = new SMESH::ListOfGroups();
1216
1217   // Python Dump
1218   TPythonDump aPythonDump;
1219   if ( !_mapGroups.empty() )
1220   {
1221     aPythonDump << "[ ";
1222     try {
1223       aList->length( _mapGroups.size() );
1224       int i = 0;
1225       map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.begin();
1226       for ( ; it != _mapGroups.end(); it++ ) {
1227         if ( CORBA::is_nil( it->second )) continue;
1228         aList[i++] = SMESH::SMESH_GroupBase::_duplicate( it->second );
1229         // Python Dump
1230         if (i > 1) aPythonDump << ", ";
1231         aPythonDump << it->second;
1232       }
1233       aList->length( i );
1234     }
1235     catch(SALOME_Exception & S_ex) {
1236       THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
1237     }
1238     aPythonDump << " ] = " << SMESH::SMESH_Mesh_var(_this()) << ".GetGroups()";
1239   }
1240   return aList._retn();
1241 }
1242
1243 //=============================================================================
1244 /*!
1245  *  Get number of groups existing in the mesh
1246  */
1247 //=============================================================================
1248
1249 CORBA::Long SMESH_Mesh_i::NbGroups() throw (SALOME::SALOME_Exception)
1250 {
1251   Unexpect aCatch(SALOME_SalomeException);
1252   return _mapGroups.size();
1253 }
1254
1255 //=============================================================================
1256 /*!
1257  * New group including all mesh elements present in initial groups is created.
1258  */
1259 //=============================================================================
1260
1261 SMESH::SMESH_Group_ptr SMESH_Mesh_i::UnionGroups( SMESH::SMESH_GroupBase_ptr theGroup1,
1262                                                   SMESH::SMESH_GroupBase_ptr theGroup2,
1263                                                   const char*                theName )
1264   throw (SALOME::SALOME_Exception)
1265 {
1266   SMESH::SMESH_Group_var aResGrp;
1267
1268   SMESH_TRY;
1269   if ( _preMeshInfo )
1270     _preMeshInfo->FullLoadFromFile();
1271
1272   if ( theGroup1->_is_nil() || theGroup2->_is_nil() )
1273     THROW_SALOME_CORBA_EXCEPTION("UnionGroups(): NULL Group",
1274                                  SALOME::BAD_PARAM);
1275   if ( theGroup1->GetType() != theGroup2->GetType() )
1276     THROW_SALOME_CORBA_EXCEPTION("UnionGroups(): different group types",
1277                                  SALOME::BAD_PARAM);
1278   TPythonDump pyDump;
1279
1280   // Create Union
1281   aResGrp = CreateGroup( theGroup1->GetType(), theName );
1282   if ( aResGrp->_is_nil() )
1283     return SMESH::SMESH_Group::_nil();
1284
1285   aResGrp->AddFrom( theGroup1 );
1286   aResGrp->AddFrom( theGroup2 );
1287
1288   // Update Python script
1289   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var(_this())
1290          << ".UnionGroups( " << theGroup1 << ", " << theGroup2 << ", '" << theName << "' )";
1291
1292   SMESH_CATCH( SMESH::throwCorbaException );
1293
1294   return aResGrp._retn();
1295 }
1296
1297 //=============================================================================
1298 /*!
1299  * \brief New group including all mesh elements present in initial groups is created.
1300  *  \param theGroups list of groups
1301  *  \param theName name of group to be created
1302  *  \return pointer to the new group
1303  */
1304 //=============================================================================
1305
1306 SMESH::SMESH_Group_ptr SMESH_Mesh_i::UnionListOfGroups(const SMESH::ListOfGroups& theGroups,
1307                                                        const char*                theName )
1308   throw (SALOME::SALOME_Exception)
1309 {
1310   SMESH::SMESH_Group_var aResGrp;
1311
1312   if ( _preMeshInfo )
1313     _preMeshInfo->FullLoadFromFile();
1314
1315   if ( !theName )
1316     return SMESH::SMESH_Group::_nil();
1317
1318   SMESH_TRY;
1319
1320   // check types
1321   SMESH::ElementType aType = SMESH::ALL;
1322   for ( int g = 0, n = theGroups.length(); g < n; g++ )
1323   {
1324     SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ];
1325     if ( CORBA::is_nil( aGrp ) )
1326       continue;
1327     if ( aType == SMESH::ALL )
1328       aType = aGrp->GetType();
1329     else if ( aType != aGrp->GetType() )
1330       THROW_SALOME_CORBA_EXCEPTION("UnionListOfGroups(): different group types",
1331                                    SALOME::BAD_PARAM);
1332   }
1333   if ( aType == SMESH::ALL )
1334     return SMESH::SMESH_Group::_nil();
1335
1336   TPythonDump pyDump;
1337
1338   // Create Union
1339   aResGrp = CreateGroup( aType, theName );
1340   if ( aResGrp->_is_nil() )
1341     return SMESH::SMESH_Group::_nil();
1342
1343   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var(_this()) << ".UnionListOfGroups([ ";
1344   for ( int g = 0, n = theGroups.length(); g < n; g++ )
1345   {
1346     SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ];
1347     if ( !CORBA::is_nil( aGrp ) )
1348     {
1349       aResGrp->AddFrom( aGrp );
1350       if ( g > 0 ) pyDump << ", ";
1351       pyDump << aGrp;
1352     }
1353   }
1354   pyDump << " ], '" << theName << "' )";
1355
1356   SMESH_CATCH( SMESH::throwCorbaException );
1357
1358   return aResGrp._retn();
1359 }
1360
1361 //=============================================================================
1362 /*!
1363  *  New group is created. All mesh elements that are
1364  *  present in both initial groups are added to the new one.
1365  */
1366 //=============================================================================
1367
1368 SMESH::SMESH_Group_ptr SMESH_Mesh_i::IntersectGroups( SMESH::SMESH_GroupBase_ptr theGroup1,
1369                                                       SMESH::SMESH_GroupBase_ptr theGroup2,
1370                                                       const char*                theName )
1371   throw (SALOME::SALOME_Exception)
1372 {
1373   SMESH::SMESH_Group_var aResGrp;
1374
1375   SMESH_TRY;
1376
1377   if ( _preMeshInfo )
1378     _preMeshInfo->FullLoadFromFile();
1379
1380   if ( theGroup1->_is_nil() || theGroup2->_is_nil() )
1381     THROW_SALOME_CORBA_EXCEPTION("IntersectGroups(): NULL Group",
1382                                  SALOME::BAD_PARAM);
1383   if ( theGroup1->GetType() != theGroup2->GetType() )
1384     THROW_SALOME_CORBA_EXCEPTION("IntersectGroups(): different group types",
1385                                  SALOME::BAD_PARAM);
1386   TPythonDump pyDump;
1387
1388   // Create Intersection
1389   aResGrp = CreateGroup( theGroup1->GetType(), theName );
1390   if ( aResGrp->_is_nil() )
1391     return aResGrp._retn();
1392
1393   SMESHDS_GroupBase* groupDS1 = 0;
1394   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup1 ))
1395     groupDS1 = grp_i->GetGroupDS();
1396
1397   SMESHDS_GroupBase* groupDS2 = 0;
1398   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup2 ))
1399     groupDS2 = grp_i->GetGroupDS();
1400
1401   SMESHDS_Group* resGroupDS = 0;
1402   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aResGrp ))
1403     resGroupDS = dynamic_cast<SMESHDS_Group*>( grp_i->GetGroupDS() );
1404
1405   if ( groupDS1 && groupDS2 && resGroupDS && !groupDS2->IsEmpty() )
1406   {
1407     SMDS_ElemIteratorPtr elemIt1 = groupDS1->GetElements();
1408     while ( elemIt1->more() )
1409     {
1410       const SMDS_MeshElement* e = elemIt1->next();
1411       if ( groupDS2->Contains( e ))
1412         resGroupDS->SMDSGroup().Add( e );
1413     }
1414   }
1415   // Update Python script
1416   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var(_this()) << ".IntersectGroups( "
1417          << theGroup1 << ", " << theGroup2 << ", '" << theName << "')";
1418
1419   SMESH_CATCH( SMESH::throwCorbaException );
1420
1421   return aResGrp._retn();
1422 }
1423
1424 //=============================================================================
1425 /*!
1426   \brief Intersect list of groups. New group is created. All mesh elements that
1427   are present in all initial groups simultaneously are added to the new one.
1428   \param theGroups list of groups
1429   \param theName name of group to be created
1430   \return pointer on the group
1431 */
1432 //=============================================================================
1433 SMESH::SMESH_Group_ptr
1434 SMESH_Mesh_i::IntersectListOfGroups(const SMESH::ListOfGroups& theGroups,
1435                                     const char*                theName )
1436   throw (SALOME::SALOME_Exception)
1437 {
1438   SMESH::SMESH_Group_var aResGrp;
1439
1440   SMESH_TRY;
1441
1442   if ( _preMeshInfo )
1443     _preMeshInfo->FullLoadFromFile();
1444
1445   if ( !theName )
1446     return SMESH::SMESH_Group::_nil();
1447
1448   // check types and get SMESHDS_GroupBase's
1449   SMESH::ElementType aType = SMESH::ALL;
1450   vector< SMESHDS_GroupBase* > groupVec;
1451   for ( int g = 0, n = theGroups.length(); g < n; g++ )
1452   {
1453     SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ];
1454     if ( CORBA::is_nil( aGrp ) )
1455       continue;
1456     if ( aType == SMESH::ALL )
1457       aType = aGrp->GetType();
1458     else if ( aType != aGrp->GetType() )
1459       THROW_SALOME_CORBA_EXCEPTION("IntersectListOfGroups(): different group types",
1460                                    SALOME::BAD_PARAM);
1461
1462     if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aGrp ))
1463       if ( SMESHDS_GroupBase* grpDS = grp_i->GetGroupDS() )
1464       {
1465         if ( grpDS->IsEmpty() )
1466         {
1467           groupVec.clear();
1468           break;
1469         }
1470         groupVec.push_back( grpDS );
1471       }
1472   }
1473   if ( aType == SMESH::ALL ) // all groups are nil
1474     return SMESH::SMESH_Group::_nil();
1475
1476   TPythonDump pyDump;
1477
1478   // Create a group
1479   aResGrp = CreateGroup( aType, theName );
1480
1481   SMESHDS_Group* resGroupDS = 0;
1482   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aResGrp ))
1483     resGroupDS = dynamic_cast<SMESHDS_Group*>( grp_i->GetGroupDS() );
1484   if ( !resGroupDS || groupVec.empty() )
1485     return aResGrp._retn();
1486
1487   // Fill the group
1488   size_t i, nb = groupVec.size();
1489   SMDS_ElemIteratorPtr elemIt1 = groupVec[0]->GetElements();
1490   while ( elemIt1->more() )
1491   {
1492     const SMDS_MeshElement* e = elemIt1->next();
1493     bool inAll = true;
1494     for ( i = 1; ( i < nb && inAll ); ++i )
1495       inAll = groupVec[i]->Contains( e );
1496
1497     if ( inAll )
1498       resGroupDS->SMDSGroup().Add( e );
1499   }
1500
1501   // Update Python script
1502   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var( _this() )
1503          << ".IntersectListOfGroups( " << theGroups << ", '" << theName << "' )";
1504
1505   SMESH_CATCH( SMESH::throwCorbaException );
1506
1507   return aResGrp._retn();
1508 }
1509
1510 //=============================================================================
1511 /*!
1512  *  New group is created. All mesh elements that are present in
1513  *  a main group but is not present in a tool group are added to the new one
1514  */
1515 //=============================================================================
1516
1517 SMESH::SMESH_Group_ptr SMESH_Mesh_i::CutGroups( SMESH::SMESH_GroupBase_ptr theGroup1,
1518                                                 SMESH::SMESH_GroupBase_ptr theGroup2,
1519                                                 const char*                theName )
1520   throw (SALOME::SALOME_Exception)
1521 {
1522   SMESH::SMESH_Group_var aResGrp;
1523
1524   SMESH_TRY;
1525
1526   if ( _preMeshInfo )
1527     _preMeshInfo->FullLoadFromFile();
1528
1529   if ( theGroup1->_is_nil() || theGroup2->_is_nil() )
1530     THROW_SALOME_CORBA_EXCEPTION("CutGroups(): NULL Group",
1531                                  SALOME::BAD_PARAM);
1532   if ( theGroup1->GetType() != theGroup2->GetType() )
1533     THROW_SALOME_CORBA_EXCEPTION("CutGroups(): different group types",
1534                                  SALOME::BAD_PARAM);
1535   TPythonDump pyDump;
1536
1537   aResGrp = CreateGroup( theGroup1->GetType(), theName );
1538   if ( aResGrp->_is_nil() )
1539     return aResGrp._retn();
1540
1541   SMESHDS_GroupBase* groupDS1 = 0;
1542   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup1 ))
1543     groupDS1 = grp_i->GetGroupDS();
1544
1545   SMESHDS_GroupBase* groupDS2 = 0;
1546   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup2 ))
1547     groupDS2 = grp_i->GetGroupDS();
1548
1549   SMESHDS_Group* resGroupDS = 0;
1550   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aResGrp ))
1551     resGroupDS = dynamic_cast<SMESHDS_Group*>( grp_i->GetGroupDS() );
1552
1553   if ( groupDS1 && groupDS2 && resGroupDS )
1554   {
1555     SMDS_ElemIteratorPtr elemIt1 = groupDS1->GetElements();
1556     while ( elemIt1->more() )
1557     {
1558       const SMDS_MeshElement* e = elemIt1->next();
1559       if ( !groupDS2->Contains( e ))
1560         resGroupDS->SMDSGroup().Add( e );
1561     }
1562   }
1563   // Update Python script
1564   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var(_this()) << ".CutGroups( "
1565          << theGroup1 << ", " << theGroup2 << ", '" << theName << "')";
1566
1567   SMESH_CATCH( SMESH::throwCorbaException );
1568
1569   return aResGrp._retn();
1570 }
1571
1572 //=============================================================================
1573 /*!
1574   \brief Cut lists of groups. New group is created. All mesh elements that are
1575   present in main groups but do not present in tool groups are added to the new one
1576   \param theMainGroups list of main groups
1577   \param theToolGroups list of tool groups
1578   \param theName name of group to be created
1579   \return pointer on the group
1580 */
1581 //=============================================================================
1582 SMESH::SMESH_Group_ptr
1583 SMESH_Mesh_i::CutListOfGroups(const SMESH::ListOfGroups& theMainGroups,
1584                               const SMESH::ListOfGroups& theToolGroups,
1585                               const char*                theName )
1586   throw (SALOME::SALOME_Exception)
1587 {
1588   SMESH::SMESH_Group_var aResGrp;
1589
1590   SMESH_TRY;
1591
1592   if ( _preMeshInfo )
1593     _preMeshInfo->FullLoadFromFile();
1594
1595   if ( !theName )
1596     return SMESH::SMESH_Group::_nil();
1597
1598   // check types and get SMESHDS_GroupBase's
1599   SMESH::ElementType aType = SMESH::ALL;
1600   vector< SMESHDS_GroupBase* >   toolGroupVec;
1601   vector< SMDS_ElemIteratorPtr > mainIterVec;
1602
1603   for ( int g = 0, n = theMainGroups.length(); g < n; g++ )
1604   {
1605     SMESH::SMESH_GroupBase_var aGrp = theMainGroups[ g ];
1606     if ( CORBA::is_nil( aGrp ) )
1607       continue;
1608     if ( aType == SMESH::ALL )
1609       aType = aGrp->GetType();
1610     else if ( aType != aGrp->GetType() )
1611       THROW_SALOME_CORBA_EXCEPTION("CutListOfGroups(): different group types",
1612                                    SALOME::BAD_PARAM);
1613     if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aGrp ))
1614       if ( SMESHDS_GroupBase* grpDS = grp_i->GetGroupDS() )
1615         if ( !grpDS->IsEmpty() )
1616           mainIterVec.push_back( grpDS->GetElements() );
1617   }
1618   if ( aType == SMESH::ALL ) // all main groups are nil
1619     return SMESH::SMESH_Group::_nil();
1620   if ( mainIterVec.empty() ) // all main groups are empty
1621     return aResGrp._retn();
1622
1623   for ( int g = 0, n = theToolGroups.length(); g < n; g++ )
1624   {
1625     SMESH::SMESH_GroupBase_var aGrp = theToolGroups[ g ];
1626     if ( CORBA::is_nil( aGrp ) )
1627       continue;
1628     if ( aType != aGrp->GetType() )
1629       THROW_SALOME_CORBA_EXCEPTION("CutListOfGroups(): different group types",
1630                                    SALOME::BAD_PARAM);
1631     if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aGrp ))
1632       if ( SMESHDS_GroupBase* grpDS = grp_i->GetGroupDS() )
1633         toolGroupVec.push_back( grpDS );
1634   }
1635
1636   TPythonDump pyDump;
1637
1638   // Create a group
1639   aResGrp = CreateGroup( aType, theName );
1640
1641   SMESHDS_Group* resGroupDS = 0;
1642   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aResGrp ))
1643     resGroupDS = dynamic_cast<SMESHDS_Group*>( grp_i->GetGroupDS() );
1644   if ( !resGroupDS )
1645     return aResGrp._retn();
1646
1647   // Fill the group
1648   size_t i, nb = toolGroupVec.size();
1649   SMDS_ElemIteratorPtr mainElemIt
1650     ( new SMDS_IteratorOnIterators
1651       < const SMDS_MeshElement*, vector< SMDS_ElemIteratorPtr > >( mainIterVec ));
1652   while ( mainElemIt->more() )
1653   {
1654     const SMDS_MeshElement* e = mainElemIt->next();
1655     bool isIn = false;
1656     for ( i = 0; ( i < nb && !isIn ); ++i )
1657       isIn = toolGroupVec[i]->Contains( e );
1658
1659     if ( !isIn )
1660       resGroupDS->SMDSGroup().Add( e );
1661   }
1662
1663   // Update Python script
1664   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var( _this() )
1665          << ".CutListOfGroups( " << theMainGroups << ", "
1666          << theToolGroups << ", '" << theName << "' )";
1667
1668   SMESH_CATCH( SMESH::throwCorbaException );
1669
1670   return aResGrp._retn();
1671 }
1672
1673 namespace // functions making checks according to SMESH::NB_COMMON_NODES_ENUM
1674 {
1675   bool isAllNodesCommon(int nbChecked, int nbCommon, int nbNodes, int nbCorners,
1676                         bool & toStopChecking )
1677   {
1678     toStopChecking = ( nbCommon < nbChecked );
1679     return nbCommon == nbNodes;
1680   }
1681   bool isMainNodesCommon(int nbChecked, int nbCommon, int nbNodes, int nbCorners,
1682                          bool & toStopChecking )
1683   {
1684     toStopChecking = ( nbCommon < nbChecked || nbChecked >= nbCorners );
1685     return nbCommon == nbCorners;
1686   }
1687   bool isAtLeastOneNodeCommon(int nbChecked, int nbCommon, int nbNodes, int nbCorners,
1688                               bool & toStopChecking )
1689   {
1690     return nbCommon > 0;
1691   }
1692   bool isMajorityOfNodesCommon(int nbChecked, int nbCommon, int nbNodes, int nbCorners,
1693                                bool & toStopChecking )
1694   {
1695     return nbCommon >= (nbNodes+1) / 2;
1696   }
1697 }
1698
1699 //=============================================================================
1700 /*!
1701  * Create a group of entities basing on nodes of other groups.
1702  *  \param [in] theGroups - list of either groups, sub-meshes or filters.
1703  *  \param [in] anElemType - a type of elements to include to the new group.
1704  *  \param [in] theName - a name of the new group.
1705  *  \param [in] theNbCommonNodes - criterion of inclusion of an element to the new group.
1706  *  \param [in] theUnderlyingOnly - if \c True, an element is included to the
1707  *         new group provided that it is based on nodes of an element of \a aListOfGroups
1708  *  \return SMESH_Group - the created group
1709 */
1710 // IMP 19939, bug 22010, IMP 22635
1711 //=============================================================================
1712
1713 SMESH::SMESH_Group_ptr
1714 SMESH_Mesh_i::CreateDimGroup(const SMESH::ListOfIDSources& theGroups,
1715                              SMESH::ElementType            theElemType,
1716                              const char*                   theName,
1717                              SMESH::NB_COMMON_NODES_ENUM   theNbCommonNodes,
1718                              CORBA::Boolean                theUnderlyingOnly)
1719   throw (SALOME::SALOME_Exception)
1720 {
1721   SMESH::SMESH_Group_var aResGrp;
1722
1723   SMESH_TRY;
1724   if ( _preMeshInfo )
1725     _preMeshInfo->FullLoadFromFile();
1726
1727   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
1728
1729   if ( !theName || !aMeshDS )
1730     return SMESH::SMESH_Group::_nil();
1731
1732   SMDSAbs_ElementType anElemType = (SMDSAbs_ElementType)theElemType;
1733
1734   bool (*isToInclude)(int nbChecked, int nbCommon, int nbNodes, int nbCorners, bool & toStop);
1735   SMESH_Comment nbCoNoStr( "SMESH.");
1736   switch ( theNbCommonNodes ) {
1737   case SMESH::ALL_NODES   : isToInclude = isAllNodesCommon;        nbCoNoStr<<"ALL_NODES"   ;break;
1738   case SMESH::MAIN        : isToInclude = isMainNodesCommon;       nbCoNoStr<<"MAIN"        ;break;
1739   case SMESH::AT_LEAST_ONE: isToInclude = isAtLeastOneNodeCommon;  nbCoNoStr<<"AT_LEAST_ONE";break;
1740   case SMESH::MAJORITY    : isToInclude = isMajorityOfNodesCommon; nbCoNoStr<<"MAJORITY"    ;break;
1741   default: return aResGrp._retn();
1742   }
1743   int nbChecked, nbCommon, nbNodes, nbCorners;
1744
1745   // Create a group
1746
1747   TPythonDump pyDump;
1748
1749   aResGrp = CreateGroup( theElemType, theName );
1750   if ( aResGrp->_is_nil() )
1751     return SMESH::SMESH_Group::_nil();
1752
1753   SMESHDS_GroupBase* groupBaseDS =
1754     SMESH::DownCast<SMESH_GroupBase_i*>( aResGrp )->GetGroupDS();
1755   SMDS_MeshGroup& resGroupCore = static_cast< SMESHDS_Group* >( groupBaseDS )->SMDSGroup();
1756
1757   vector<bool> isNodeInGroups;
1758
1759   for ( int g = 0, n = theGroups.length(); g < n; g++ ) // loop on theGroups
1760   {
1761     SMESH::SMESH_IDSource_var aGrp = theGroups[ g ];
1762     if ( CORBA::is_nil( aGrp ) )
1763       continue;
1764     SMESH::SMESH_Mesh_var mesh = aGrp->GetMesh();
1765     if ( mesh->_is_nil() || mesh->GetId() != this->GetId() )
1766       continue;
1767
1768     SMDS_ElemIteratorPtr elIt = GetElements( aGrp, SMESH::ALL );
1769     if ( !elIt ) continue;
1770
1771     if ( theElemType == SMESH::NODE ) // get all nodes of elements
1772     {
1773       while ( elIt->more() ) {
1774         const SMDS_MeshElement* el = elIt->next();
1775         SMDS_ElemIteratorPtr nIt = el->nodesIterator();
1776         while ( nIt->more() )
1777           resGroupCore.Add( nIt->next() );
1778       }
1779     }
1780     // get elements of theElemType based on nodes of every element of group
1781     else if ( theUnderlyingOnly )
1782     {
1783       while ( elIt->more() )
1784       {
1785         const SMDS_MeshElement* el = elIt->next(); // an element of ref group
1786         TIDSortedElemSet elNodes( el->begin_nodes(), el->end_nodes() );
1787         TIDSortedElemSet checkedElems;
1788         SMDS_NodeIteratorPtr nIt = el->nodeIterator();
1789         while ( nIt->more() )
1790         {
1791           const SMDS_MeshNode* n = nIt->next();
1792           SMDS_ElemIteratorPtr elOfTypeIt = n->GetInverseElementIterator( anElemType );
1793           // check nodes of elements of theElemType around el
1794           while ( elOfTypeIt->more() )
1795           {
1796             const SMDS_MeshElement* elOfType = elOfTypeIt->next();
1797             if ( !checkedElems.insert( elOfType ).second ) continue;
1798             nbNodes   = elOfType->NbNodes();
1799             nbCorners = elOfType->NbCornerNodes();
1800             nbCommon  = 0;
1801             bool toStopChecking = false;
1802             SMDS_ElemIteratorPtr nIt2 = elOfType->nodesIterator();
1803             for ( nbChecked = 1; nIt2->more() && !toStopChecking; ++nbChecked )
1804               if ( elNodes.count( nIt2->next() ) &&
1805                    isToInclude( nbChecked, ++nbCommon, nbNodes, nbCorners, toStopChecking ))
1806               {
1807                 resGroupCore.Add( elOfType );
1808                 break;
1809               }
1810           }
1811         }
1812       }
1813     }
1814     // get all nodes of elements of groups
1815     else
1816     {
1817       while ( elIt->more() )
1818       {
1819         const SMDS_MeshElement* el = elIt->next(); // an element of group
1820         SMDS_NodeIteratorPtr nIt = el->nodeIterator();
1821         while ( nIt->more() )
1822         {
1823           const SMDS_MeshNode* n = nIt->next();
1824           if ( n->GetID() >= (int) isNodeInGroups.size() )
1825             isNodeInGroups.resize( n->GetID() + 1, false );
1826           isNodeInGroups[ n->GetID() ] = true;
1827         }
1828       }
1829     }
1830   }
1831
1832   // Get elements of theElemType based on a certain number of nodes of elements of groups
1833   if ( !theUnderlyingOnly && !isNodeInGroups.empty() )
1834   {
1835     const SMDS_MeshNode* n;
1836     vector<bool> isElemChecked( aMeshDS->MaxElementID() + 1 );
1837     const int isNodeInGroupsSize = isNodeInGroups.size();
1838     for ( int iN = 0; iN < isNodeInGroupsSize; ++iN )
1839     {
1840       if ( !isNodeInGroups[ iN ] ||
1841            !( n = aMeshDS->FindNode( iN )))
1842         continue;
1843
1844       // check nodes of elements of theElemType around n
1845       SMDS_ElemIteratorPtr elOfTypeIt = n->GetInverseElementIterator( anElemType );
1846       while ( elOfTypeIt->more() )
1847       {
1848         const SMDS_MeshElement*  elOfType = elOfTypeIt->next();
1849         vector<bool>::reference isChecked = isElemChecked[ elOfType->GetID() ];
1850         if ( isChecked )
1851           continue;
1852         isChecked = true;
1853
1854         nbNodes   = elOfType->NbNodes();
1855         nbCorners = elOfType->NbCornerNodes();
1856         nbCommon  = 0;
1857         bool toStopChecking = false;
1858         SMDS_ElemIteratorPtr nIt = elOfType->nodesIterator();
1859         for ( nbChecked = 1; nIt->more() && !toStopChecking; ++nbChecked )
1860         {
1861           const int nID = nIt->next()->GetID();
1862           if ( nID < isNodeInGroupsSize && isNodeInGroups[ nID ] &&
1863                isToInclude( nbChecked, ++nbCommon, nbNodes, nbCorners, toStopChecking ))
1864           {
1865             resGroupCore.Add( elOfType );
1866             break;
1867           }
1868         }
1869       }
1870     }
1871   }
1872
1873   // Update Python script
1874   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var( _this())
1875          << ".CreateDimGroup( "
1876          << theGroups << ", " << theElemType << ", '" << theName << "', "
1877          << nbCoNoStr << ", " << theUnderlyingOnly << ")";
1878
1879   SMESH_CATCH( SMESH::throwCorbaException );
1880
1881   return aResGrp._retn();
1882 }
1883
1884 //================================================================================
1885 /*!
1886  * \brief Distribute all faces of the mesh between groups using sharp edges and optionally
1887  *        existing 1D elements as group boundaries.
1888  *  \param [in] theSharpAngle - edge is considered sharp if an angle between normals of
1889  *              adjacent faces is more than \a sharpAngle in degrees.
1890  *  \param [in] theCreateEdges - to create 1D elements for detected sharp edges.
1891  *  \param [in] theUseExistingEdges - to use existing edges as group boundaries
1892  *  \return ListOfGroups - the created groups
1893  */
1894 //================================================================================
1895
1896 SMESH::ListOfGroups*
1897 SMESH_Mesh_i::FaceGroupsSeparatedByEdges( CORBA::Double  theSharpAngle,
1898                                           CORBA::Boolean theCreateEdges,
1899                                           CORBA::Boolean theUseExistingEdges )
1900   throw (SALOME::SALOME_Exception)
1901 {
1902   if ( theSharpAngle < 0 || theSharpAngle > 180 )
1903     THROW_SALOME_CORBA_EXCEPTION("Invalid sharp angle, it must be between 0 and 180 degrees",
1904                                  SALOME::BAD_PARAM);
1905
1906   SMESH::ListOfGroups_var resultGroups = new SMESH::ListOfGroups;
1907
1908   TPythonDump pyDump;
1909
1910   SMESH_TRY;
1911   if ( _preMeshInfo )
1912     _preMeshInfo->FullLoadFromFile();
1913
1914   SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
1915
1916   std::vector< SMESH_MeshAlgos::Edge > edges =
1917     SMESH_MeshAlgos::FindSharpEdges( meshDS, theSharpAngle, theUseExistingEdges );
1918
1919   if ( theCreateEdges )
1920   {
1921     std::vector<const SMDS_MeshNode *> nodes(2);
1922     for ( size_t i = 0; i < edges.size(); ++i )
1923     {
1924       nodes[0] = edges[i]._node1;
1925       nodes[1] = edges[i]._node2;
1926       if ( meshDS->FindElement( nodes, SMDSAbs_Edge ))
1927         continue;
1928       if ( edges[i]._medium )
1929         meshDS->AddEdge( edges[i]._node1, edges[i]._node2, edges[i]._medium );
1930       else
1931         meshDS->AddEdge( edges[i]._node1, edges[i]._node2 );
1932     }
1933   }
1934
1935   std::vector< std::vector< const SMDS_MeshElement* > > faceGroups =
1936     SMESH_MeshAlgos::SeparateFacesByEdges( meshDS, edges );
1937
1938   SMESH::SMESH_MeshEditor_var editor = GetMeshEditor(); // create _editor
1939
1940   resultGroups->length( faceGroups.size() );
1941   for ( size_t iG = 0; iG < faceGroups.size(); ++iG )
1942   {
1943     SMESH::SMESH_Group_var group = CreateGroup( SMESH::FACE,
1944                                                 _editor->GenerateGroupName("Group").c_str());
1945     resultGroups[iG] = SMESH::SMESH_Group::_duplicate( group );
1946
1947     SMESHDS_GroupBase* groupBaseDS =
1948       SMESH::DownCast<SMESH_GroupBase_i*>( group )->GetGroupDS();
1949     SMDS_MeshGroup& groupCore = static_cast< SMESHDS_Group* >( groupBaseDS )->SMDSGroup();
1950
1951     std::vector< const SMDS_MeshElement* >& faces = faceGroups[ iG ];
1952     for ( size_t i = 0; i < faces.size(); ++i )
1953       groupCore.Add( faces[i] );
1954   }
1955
1956   pyDump << resultGroups << " = " << SMESH::SMESH_Mesh_var(_this())
1957          << ".FaceGroupsSeparatedByEdges( "
1958          << TVar( theSharpAngle ) << ", "
1959          << theCreateEdges << ", "
1960          << theUseExistingEdges << " )";
1961
1962   SMESH_CATCH( SMESH::throwCorbaException );
1963   return resultGroups._retn();
1964
1965 }
1966
1967 //================================================================================
1968 /*!
1969  * \brief Remember GEOM group data
1970  */
1971 //================================================================================
1972
1973 void SMESH_Mesh_i::addGeomGroupData(GEOM::GEOM_Object_ptr theGeomObj,
1974                                     CORBA::Object_ptr     theSmeshObj)
1975 {
1976   if ( CORBA::is_nil( theGeomObj ) || theGeomObj->GetType() != GEOM_GROUP )
1977     return;
1978   // group SO
1979   SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( theGeomObj );
1980   if ( groupSO->_is_nil() )
1981     return;
1982   // group indices
1983   GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine();
1984   GEOM::GEOM_IGroupOperations_wrap groupOp =
1985     geomGen->GetIGroupOperations();
1986   GEOM::ListOfLong_var ids = groupOp->GetObjects( theGeomObj );
1987
1988   // store data
1989   _geomGroupData.push_back( TGeomGroupData() );
1990   TGeomGroupData & groupData = _geomGroupData.back();
1991   // entry
1992   CORBA::String_var entry = groupSO->GetID();
1993   groupData._groupEntry = entry.in();
1994   // indices
1995   for ( CORBA::ULong i = 0; i < ids->length(); ++i )
1996     groupData._indices.insert( ids[i] );
1997   // SMESH object
1998   groupData._smeshObject = CORBA::Object::_duplicate( theSmeshObj );
1999   // shape index in SMESHDS
2000   // TopoDS_Shape shape = _gen_i->GeomObjectToShape( theGeomObj );
2001   // groupData._dsID = shape.IsNull() ? 0 : _impl->GetSubMesh( shape )->GetId();
2002 }
2003
2004 //================================================================================
2005 /*!
2006  * Remove GEOM group data relating to removed smesh object
2007  */
2008 //================================================================================
2009
2010 void SMESH_Mesh_i::removeGeomGroupData(CORBA::Object_ptr theSmeshObj)
2011 {
2012   list<TGeomGroupData>::iterator
2013     data = _geomGroupData.begin(), dataEnd = _geomGroupData.end();
2014   for ( ; data != dataEnd; ++data ) {
2015     if ( theSmeshObj->_is_equivalent( data->_smeshObject )) {
2016       _geomGroupData.erase( data );
2017       return;
2018     }
2019   }
2020 }
2021
2022 //================================================================================
2023 /*!
2024  * \brief Return new group contents if it has been changed and update group data
2025  */
2026 //================================================================================
2027
2028 TopoDS_Shape SMESH_Mesh_i::newGroupShape( TGeomGroupData & groupData)
2029 {
2030   TopoDS_Shape newShape;
2031
2032   // get geom group
2033   SALOMEDS::SObject_wrap groupSO = SMESH_Gen_i::getStudyServant()->FindObjectID( groupData._groupEntry.c_str() );
2034   if ( !groupSO->_is_nil() )
2035   {
2036     CORBA::Object_var groupObj = _gen_i->SObjectToObject( groupSO );
2037     if ( CORBA::is_nil( groupObj )) return newShape;
2038     GEOM::GEOM_Object_var geomGroup = GEOM::GEOM_Object::_narrow( groupObj );
2039
2040     // get indices of group items
2041     set<int> curIndices;
2042     GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine();
2043     GEOM::GEOM_IGroupOperations_wrap groupOp =
2044       geomGen->GetIGroupOperations();
2045     GEOM::ListOfLong_var   ids = groupOp->GetObjects( geomGroup );
2046     for ( CORBA::ULong i = 0; i < ids->length(); ++i )
2047       curIndices.insert( ids[i] );
2048
2049     if ( groupData._indices == curIndices )
2050       return newShape; // group not changed
2051
2052     // update data
2053     groupData._indices = curIndices;
2054
2055     GEOM_Client* geomClient = _gen_i->GetShapeReader();
2056     if ( !geomClient ) return newShape;
2057     CORBA::String_var groupIOR = geomGen->GetStringFromIOR( geomGroup );
2058     geomClient->RemoveShapeFromBuffer( groupIOR.in() );
2059     newShape = _gen_i->GeomObjectToShape( geomGroup );
2060   }
2061
2062   if ( newShape.IsNull() ) {
2063     // geom group becomes empty - return empty compound
2064     TopoDS_Compound compound;
2065     BRep_Builder().MakeCompound(compound);
2066     newShape = compound;
2067   }
2068   return newShape;
2069 }
2070
2071 namespace
2072 {
2073   //-----------------------------------------------------------------------------
2074   /*!
2075    * \brief Storage of shape and index used in CheckGeomGroupModif()
2076    */
2077   struct TIndexedShape
2078   {
2079     int          _index;
2080     TopoDS_Shape _shape;
2081     TIndexedShape( int i, const TopoDS_Shape& s ):_index(i), _shape(s) {}
2082   };
2083   //-----------------------------------------------------------------------------
2084   /*!
2085    * \brief Data to re-create a group on geometry
2086    */
2087   struct TGroupOnGeomData
2088   {
2089     int                 _oldID;
2090     TopoDS_Shape        _shape;
2091     SMDSAbs_ElementType _type;
2092     std::string         _name;
2093     Quantity_Color      _color;
2094
2095     TGroupOnGeomData( const SMESHDS_GroupOnGeom* group )
2096     {
2097       _oldID = group->GetID();
2098       _type  = group->GetType();
2099       _name  = group->GetStoreName();
2100       _color = group->GetColor();
2101     }
2102   };
2103
2104   //-----------------------------------------------------------------------------
2105   /*!
2106    * \brief Check if a filter is still valid after geometry removal
2107    */
2108   bool isValidGeomFilter( SMESH::Filter_var theFilter )
2109   {
2110     if ( theFilter->_is_nil() )
2111       return false;
2112     SMESH::Filter::Criteria_var criteria;
2113     theFilter->GetCriteria( criteria.out() );
2114
2115     for ( CORBA::ULong iCr = 0; iCr < criteria->length(); ++iCr )
2116     {
2117       const char* thresholdID = criteria[ iCr ].ThresholdID.in();
2118       std::string entry;
2119       switch ( criteria[ iCr ].Type )
2120       {
2121       case SMESH::FT_BelongToGeom:
2122       case SMESH::FT_BelongToPlane:
2123       case SMESH::FT_BelongToCylinder:
2124       case SMESH::FT_BelongToGenSurface:
2125       case SMESH::FT_LyingOnGeom:
2126         entry = thresholdID;
2127         break;
2128       case SMESH::FT_ConnectedElements:
2129         if ( thresholdID )
2130         {
2131           entry = thresholdID;
2132           break;
2133         }
2134       default:
2135         continue;
2136       }
2137       SMESH_Gen_i*           gen = SMESH_Gen_i::GetSMESHGen();
2138       SALOMEDS::SObject_wrap  so = gen->getStudyServant()->FindObjectID( entry.c_str() );
2139       if ( so->_is_nil() )
2140         return false;
2141       CORBA::Object_var      obj = so->GetObject();
2142       GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( obj );
2143       if ( gen->GeomObjectToShape( geom ).IsNull() )
2144         return false;
2145
2146     } // loop on criteria
2147
2148     return true;
2149   }
2150 }
2151
2152 //=============================================================================
2153 /*!
2154  * \brief Update data if geometry changes
2155  *
2156  * Issue 0022501
2157  */
2158 //=============================================================================
2159
2160 void SMESH_Mesh_i::CheckGeomModif()
2161 {
2162   SMESH::SMESH_Mesh_var me = _this();
2163   GEOM::GEOM_Object_var mainGO = GetShapeToMesh();
2164
2165   //bool removedFromClient = false;
2166
2167   if ( mainGO->_is_nil() ) // GEOM_Client cleared or geometry removed? (IPAL52735, PAL23636)
2168   {
2169     //removedFromClient = _impl->HasShapeToMesh();
2170
2171     // try to find geometry by study reference
2172     SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( me );
2173     SALOMEDS::SObject_wrap geomRefSO, geomSO;
2174     if ( !meshSO->_is_nil() &&
2175          meshSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
2176          geomRefSO->ReferencedObject( geomSO.inout() ))
2177     {
2178       CORBA::Object_var geomObj = _gen_i->SObjectToObject( geomSO );
2179       mainGO = GEOM::GEOM_Object::_narrow( geomObj );
2180     }
2181
2182     if ( mainGO->_is_nil() &&    // geometry removed ==>
2183          !geomRefSO->_is_nil() ) // remove geom dependent data: sub-meshes etc.
2184     {
2185       // convert geom dependent groups into standalone ones
2186       CheckGeomGroupModif();
2187
2188       _impl->ShapeToMesh( TopoDS_Shape() );
2189
2190       // remove sub-meshes
2191       std::map<int, SMESH::SMESH_subMesh_ptr>::iterator i_sm = _mapSubMeshIor.begin();
2192       while ( i_sm != _mapSubMeshIor.end() )
2193       {
2194         SMESH::SMESH_subMesh_ptr sm = i_sm->second;
2195         ++i_sm;
2196         RemoveSubMesh( sm );
2197       }
2198       // remove all children except groups in the study
2199       SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
2200       SALOMEDS::SObject_wrap so;
2201       for ( CORBA::Long tag = SMESH::Tag_RefOnShape; tag <= SMESH::Tag_LastSubMesh; ++tag )
2202         if ( meshSO->FindSubObject( tag, so.inout() ))
2203           builder->RemoveObjectWithChildren( so );
2204
2205       _gen_i->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED" );
2206
2207       return;
2208     }
2209   }
2210
2211   if ( !_impl->HasShapeToMesh() ) return;
2212
2213
2214   // Update after group modification
2215
2216   if ( mainGO->GetType() == GEOM_GROUP ||    // is group or not modified
2217        mainGO->GetTick() == _mainShapeTick )
2218   {
2219     int nb = NbNodes() + NbElements();
2220     CheckGeomGroupModif();
2221     if ( nb != NbNodes() + NbElements() ) // something removed due to hypotheses change
2222       _gen_i->UpdateIcons( me );
2223     return;
2224   }
2225
2226   // Update after shape transformation like Translate
2227
2228   GEOM_Client* geomClient = _gen_i->GetShapeReader();
2229   if ( !geomClient ) return;
2230   GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine();
2231   if ( geomGen->_is_nil() ) return;
2232
2233   CORBA::String_var ior = geomGen->GetStringFromIOR( mainGO );
2234   geomClient->RemoveShapeFromBuffer( ior.in() );
2235
2236   // Update data taking into account that
2237   // all sub-shapes change but IDs of sub-shapes remain (except for geom groups)
2238
2239   _impl->Clear();
2240   TopoDS_Shape newShape = _gen_i->GeomObjectToShape( mainGO );
2241   if ( newShape.IsNull() )
2242     return;
2243
2244   _mainShapeTick = mainGO->GetTick();
2245
2246   SMESHDS_Mesh * meshDS = _impl->GetMeshDS();
2247
2248   // store data of groups on geometry
2249   std::vector< TGroupOnGeomData > groupsData;
2250   const std::set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
2251   groupsData.reserve( groups.size() );
2252   std::set<SMESHDS_GroupBase*>::const_iterator g = groups.begin();
2253   for ( ; g != groups.end(); ++g )
2254   {
2255     if ( const SMESHDS_GroupOnGeom* group = dynamic_cast< SMESHDS_GroupOnGeom* >( *g ))
2256     {
2257       groupsData.push_back( TGroupOnGeomData( group ));
2258
2259       // get a new shape
2260       SMESH::SMESH_GroupOnGeom_var gog;
2261       std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.find( group->GetID() );
2262       if ( i_grp != _mapGroups.end() )
2263         gog = SMESH::SMESH_GroupOnGeom::_narrow( i_grp->second );
2264
2265       GEOM::GEOM_Object_var geom;
2266       if ( !gog->_is_nil() )
2267         geom = gog->GetShape();
2268       if ( !geom->_is_nil() )
2269       {
2270         CORBA::String_var ior = geomGen->GetStringFromIOR( geom );
2271         geomClient->RemoveShapeFromBuffer( ior.in() );
2272         groupsData.back()._shape = _gen_i->GeomObjectToShape( geom );
2273       }
2274     }
2275   }
2276   // store assigned hypotheses
2277   std::vector< pair< int, THypList > > ids2Hyps;
2278   const ShapeToHypothesis & hyps = meshDS->GetHypotheses();
2279   for ( ShapeToHypothesis::Iterator s2hyps( hyps ); s2hyps.More(); s2hyps.Next() )
2280   {
2281     const TopoDS_Shape& s = s2hyps.Key();
2282     const THypList&  hyps = s2hyps.ChangeValue();
2283     ids2Hyps.push_back( make_pair( meshDS->ShapeToIndex( s ), hyps ));
2284   }
2285
2286   // change shape to mesh
2287   int oldNbSubShapes = meshDS->MaxShapeIndex();
2288   _impl->ShapeToMesh( TopoDS_Shape() );
2289   _impl->ShapeToMesh( newShape );
2290
2291   // re-add shapes of geom groups
2292   std::list<TGeomGroupData>::iterator data = _geomGroupData.begin();
2293   for ( ; data != _geomGroupData.end(); ++data )
2294   {
2295     TopoDS_Shape newShape = newGroupShape( *data );
2296     if ( !newShape.IsNull() )
2297     {
2298       if ( meshDS->ShapeToIndex( newShape ) > 0 ) // a group reduced to one sub-shape
2299       {
2300         TopoDS_Compound compound;
2301         BRep_Builder().MakeCompound( compound );
2302         BRep_Builder().Add( compound, newShape );
2303         newShape = compound;
2304       }
2305       _impl->GetSubMesh( newShape );
2306     }
2307   }
2308   if ( oldNbSubShapes != meshDS->MaxShapeIndex() )
2309     THROW_SALOME_CORBA_EXCEPTION( "SMESH_Mesh_i::CheckGeomModif() bug",
2310                                   SALOME::INTERNAL_ERROR );
2311
2312   // re-assign hypotheses
2313   for ( size_t i = 0; i < ids2Hyps.size(); ++i )
2314   {
2315     const TopoDS_Shape& s = meshDS->IndexToShape( ids2Hyps[i].first );
2316     const THypList&  hyps = ids2Hyps[i].second;
2317     THypList::const_iterator h = hyps.begin();
2318     for ( ; h != hyps.end(); ++h )
2319       _impl->AddHypothesis( s, (*h)->GetID() );
2320   }
2321
2322   // restore groups on geometry
2323   for ( size_t i = 0; i < groupsData.size(); ++i )
2324   {
2325     const TGroupOnGeomData& data = groupsData[i];
2326     if ( data._shape.IsNull() )
2327       continue;
2328
2329     std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i2g = _mapGroups.find( data._oldID );
2330     if ( i2g == _mapGroups.end() ) continue;
2331
2332     SMESH_GroupBase_i* gr_i = SMESH::DownCast<SMESH_GroupBase_i*>( i2g->second );
2333     if ( !gr_i ) continue;
2334
2335     SMESH_Group* g = _impl->AddGroup( data._type, data._name.c_str(), data._oldID, data._shape );
2336     if ( !g )
2337       _mapGroups.erase( i2g );
2338     else
2339       g->GetGroupDS()->SetColor( data._color );
2340   }
2341
2342   // update _mapSubMesh
2343   std::map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
2344   for ( ; i_sm != _mapSubMesh.end(); ++i_sm )
2345     i_sm->second = _impl->GetSubMesh( meshDS->IndexToShape( i_sm->first ));
2346
2347 }
2348
2349 //=============================================================================
2350 /*!
2351  * \brief Update objects depending on changed geom groups
2352  *
2353  * NPAL16168: geometrical group edition from a submesh don't modify mesh computation
2354  * issue 0020210: Update of a smesh group after modification of the associated geom group
2355  */
2356 //=============================================================================
2357
2358 void SMESH_Mesh_i::CheckGeomGroupModif()
2359 {
2360   // remove sub-meshes referring a removed sub-shapes (if main shape still exists)
2361   SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
2362   GEOM::GEOM_Object_var  mainGO = GetShapeToMesh();
2363   SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( SMESH::SMESH_Mesh_var( _this() ));
2364   if ( !mainGO->_is_nil() && !meshSO->_is_nil() )
2365   {
2366     SALOMEDS::SObject_wrap rootSO, geomRefSO, geomSO;
2367     for ( CORBA::Long tag = SMESH::Tag_FirstSubMesh; tag <= SMESH::Tag_LastSubMesh; ++tag )
2368       if ( meshSO->FindSubObject( tag, rootSO.inout() ))
2369       {
2370         int nbValid = 0, nbRemoved = 0;
2371         SALOMEDS::ChildIterator_wrap chItr = _gen_i->getStudyServant()->NewChildIterator( rootSO );
2372         for ( ; chItr->More(); chItr->Next() )
2373         {
2374           SALOMEDS::SObject_wrap smSO = chItr->Value(); // sub-mesh SO
2375           if ( !smSO->_is_nil() &&
2376                smSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
2377                geomRefSO->ReferencedObject( geomSO.inout() )) // find geometry by reference
2378           {
2379             CORBA::Object_var  geomObj = _gen_i->SObjectToObject( geomSO );
2380             GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( geomObj );
2381             if ( !geom->_non_existent() )
2382             {
2383               ++nbValid;
2384               continue; // keep the sub-mesh
2385             }
2386           }
2387           CORBA::Object_var     smObj = _gen_i->SObjectToObject( smSO );
2388           SMESH::SMESH_subMesh_var sm = SMESH::SMESH_subMesh::_narrow( smObj );
2389           if ( !sm->_is_nil() && !sm->_non_existent() )
2390           {
2391             GEOM::GEOM_Object_var smGeom = sm->GetSubShape();
2392             if ( smGeom->_is_nil() )
2393             {
2394               RemoveSubMesh( sm );
2395               ++nbRemoved;
2396             }
2397           }
2398           else
2399           {
2400             if ( _preMeshInfo )
2401               _preMeshInfo->ForgetAllData(); // unknown hypothesis modified
2402             builder->RemoveObjectWithChildren( smSO ); // sub-shape removed before loading SMESH
2403             ++nbRemoved;
2404           }
2405         }
2406         if ( /*nbRemoved > 0 &&*/ nbValid == 0 )
2407           builder->RemoveObjectWithChildren( rootSO );
2408       }
2409   }
2410
2411   // check for removed sub-shapes and convert geom dependent groups into standalone ones
2412   std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
2413   while ( i_gr != _mapGroups.end())
2414   {
2415     SMESH::SMESH_GroupBase_ptr group = i_gr->second;
2416     ++i_gr;
2417     SALOMEDS::SObject_wrap        groupSO = _gen_i->ObjectToSObject( group ), refSO;
2418     SMESH::SMESH_GroupOnGeom_var   onGeom = SMESH::SMESH_GroupOnGeom::_narrow  ( group );
2419     SMESH::SMESH_GroupOnFilter_var onFilt = SMESH::SMESH_GroupOnFilter::_narrow( group );
2420     bool isValidGeom = false;
2421     if ( !onGeom->_is_nil() )
2422     {
2423       isValidGeom = ( ! GEOM::GEOM_Object_var( onGeom->GetShape() )->_is_nil() );
2424     }
2425     else if ( !onFilt->_is_nil() )
2426     {
2427       isValidGeom = isValidGeomFilter( onFilt->GetFilter() );
2428     }
2429     else // standalone
2430     {
2431       isValidGeom = ( !groupSO->_is_nil() &&
2432                       !groupSO->FindSubObject( SMESH::Tag_RefOnShape, refSO.inout() ));
2433     }
2434     if ( !isValidGeom )
2435     {
2436       if ( !IsLoaded() || group->IsEmpty() )
2437       {
2438         RemoveGroup( group );
2439       }
2440       else if ( !onGeom->_is_nil() || !onFilt->_is_nil() )
2441       {
2442         SMESH::SMESH_Group_var ( ConvertToStandalone( group ));
2443       }
2444       else // is it possible?
2445       {
2446         builder->RemoveObjectWithChildren( refSO );
2447       }
2448     }
2449   }
2450
2451
2452   if ( !_impl->HasShapeToMesh() ) return;
2453
2454   CORBA::Long nbEntities = NbNodes() + NbElements();
2455
2456   // Check if group contents changed
2457
2458   typedef map< string, TopoDS_Shape > TEntry2Geom;
2459   TEntry2Geom newGroupContents;
2460
2461   list<TGeomGroupData>::iterator
2462     data = _geomGroupData.begin(), dataEnd = _geomGroupData.end();
2463   for ( ; data != dataEnd; ++data )
2464   {
2465     pair< TEntry2Geom::iterator, bool > it_new =
2466       newGroupContents.insert( make_pair( data->_groupEntry, TopoDS_Shape() ));
2467     bool processedGroup    = !it_new.second;
2468     TopoDS_Shape& newShape = it_new.first->second;
2469     if ( !processedGroup )
2470       newShape = newGroupShape( *data );
2471     if ( newShape.IsNull() )
2472       continue; // no changes
2473
2474     if ( _preMeshInfo )
2475       _preMeshInfo->ForgetOrLoad();
2476
2477     if ( processedGroup ) { // update group indices
2478       list<TGeomGroupData>::iterator data2 = data;
2479       for ( --data2; data2->_groupEntry != data->_groupEntry; --data2) {}
2480       data->_indices = data2->_indices;
2481     }
2482
2483     // Update SMESH objects according to new GEOM group contents
2484
2485     SMESH::SMESH_subMesh_var submesh = SMESH::SMESH_subMesh::_narrow( data->_smeshObject );
2486     if ( !submesh->_is_nil() ) // -------------- Sub mesh ---------------------
2487     {
2488       int oldID = submesh->GetId();
2489       if ( !_mapSubMeshIor.count( oldID ))
2490         continue;
2491       TopoDS_Shape oldShape = _mapSubMesh[oldID]->GetSubShape();
2492
2493       // update hypotheses
2494       list <const SMESHDS_Hypothesis * > hyps = _impl->GetHypothesisList(oldShape);
2495       list <const SMESHDS_Hypothesis * >::iterator hypIt;
2496       for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2497       {
2498         _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
2499         _impl->AddHypothesis   ( newShape, (*hypIt)->GetID());
2500       }
2501       // care of submeshes
2502       SMESH_subMesh* newSubmesh = _impl->GetSubMesh( newShape );
2503       int newID = newSubmesh->GetId();
2504       if ( newID != oldID ) {
2505         _mapSubMesh   [ newID ] = newSubmesh;
2506         _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2507         _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2508         _mapSubMesh.   erase(oldID);
2509         _mapSubMesh_i. erase(oldID);
2510         _mapSubMeshIor.erase(oldID);
2511         _mapSubMesh_i [ newID ]->changeLocalId( newID );
2512       }
2513       continue;
2514     }
2515
2516     SMESH::SMESH_GroupOnGeom_var smeshGroup =
2517       SMESH::SMESH_GroupOnGeom::_narrow( data->_smeshObject );
2518     if ( !smeshGroup->_is_nil() ) // ------------ GROUP -----------------------
2519     {
2520       SMESH_GroupOnGeom_i* group_i = SMESH::DownCast<SMESH_GroupOnGeom_i*>( smeshGroup );
2521       if ( group_i ) {
2522         ::SMESH_Group* group = _impl->GetGroup( group_i->GetLocalID() );
2523         SMESHDS_GroupOnGeom* ds = static_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() );
2524         ds->SetShape( newShape );
2525       }
2526       continue;
2527     }
2528
2529     SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( data->_smeshObject );
2530     if ( !mesh->_is_nil() ) // -------------- MESH ----------------------------
2531     {
2532       // Remove groups and submeshes basing on removed sub-shapes
2533
2534       TopTools_MapOfShape newShapeMap;
2535       TopoDS_Iterator shapeIt( newShape );
2536       for ( ; shapeIt.More(); shapeIt.Next() )
2537         newShapeMap.Add( shapeIt.Value() );
2538
2539       SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
2540       for ( shapeIt.Initialize( meshDS->ShapeToMesh() ); shapeIt.More(); shapeIt.Next() )
2541       {
2542         if ( newShapeMap.Contains( shapeIt.Value() ))
2543           continue;
2544         TopTools_IndexedMapOfShape oldShapeMap;
2545         TopExp::MapShapes( shapeIt.Value(), oldShapeMap );
2546         for ( int i = 1; i <= oldShapeMap.Extent(); ++i )
2547         {
2548           const TopoDS_Shape& oldShape = oldShapeMap(i);
2549           int oldInd = meshDS->ShapeToIndex( oldShape );
2550           // -- submeshes --
2551           map<int, SMESH::SMESH_subMesh_ptr>::iterator i_smIor = _mapSubMeshIor.find( oldInd );
2552           if ( i_smIor != _mapSubMeshIor.end() ) {
2553             RemoveSubMesh( i_smIor->second ); // one submesh per shape index
2554           }
2555           // --- groups ---
2556           map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.begin();
2557           for ( ; i_grp != _mapGroups.end(); ++i_grp )
2558           {
2559             // check if a group bases on oldInd shape
2560             SMESHDS_GroupOnGeom* grpOnGeom = 0;
2561             if ( ::SMESH_Group* g = _impl->GetGroup( i_grp->first ))
2562               grpOnGeom = dynamic_cast<SMESHDS_GroupOnGeom*>( g->GetGroupDS() );
2563             if ( grpOnGeom && oldShape.IsSame( grpOnGeom->GetShape() ))
2564             { // remove
2565               RemoveGroup( i_grp->second ); // several groups can base on same shape
2566               i_grp = _mapGroups.begin(); // _mapGroups changed - restart iteration
2567             }
2568           }
2569         }
2570       }
2571       // Reassign hypotheses and update groups after setting the new shape to mesh
2572
2573       // collect anassigned hypotheses
2574       typedef list< pair< TIndexedShape, list<const SMESHDS_Hypothesis*> > > TShapeHypList;
2575       list <const SMESHDS_Hypothesis * >::const_iterator hypIt;
2576       TShapeHypList assignedHyps;
2577       for ( int i = 1; i <= meshDS->MaxShapeIndex(); ++i )
2578       {
2579         const TopoDS_Shape& oldShape = meshDS->IndexToShape(i);
2580         list<const SMESHDS_Hypothesis*> hyps = meshDS->GetHypothesis( oldShape );// copy
2581         if ( !hyps.empty() ) {
2582           assignedHyps.push_back( make_pair( TIndexedShape(i,oldShape), hyps ));
2583           for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2584             _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
2585         }
2586       }
2587       // collect shapes supporting groups
2588       typedef list < pair< TIndexedShape, SMDSAbs_ElementType > > TShapeTypeList;
2589       TShapeTypeList groupData;
2590       const set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
2591       set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2592       for ( ; grIt != groups.end(); ++grIt )
2593       {
2594         if ( SMESHDS_GroupOnGeom* gog = dynamic_cast<SMESHDS_GroupOnGeom*>( *grIt ))
2595           groupData.push_back
2596             ( make_pair( TIndexedShape( gog->GetID(),gog->GetShape()), gog->GetType()));
2597       }
2598       // set new shape to mesh -> DS of sub-meshes and geom groups is deleted
2599       _impl->Clear();
2600       _impl->ShapeToMesh( TopoDS_Shape() ); // IPAL52730
2601       _impl->ShapeToMesh( newShape );
2602
2603       // reassign hypotheses
2604       TShapeHypList::iterator indS_hyps = assignedHyps.begin();
2605       for ( ; indS_hyps != assignedHyps.end(); ++indS_hyps )
2606       {
2607         TIndexedShape&                   geom = indS_hyps->first;
2608         list<const SMESHDS_Hypothesis*>& hyps = indS_hyps->second;
2609         int oldID = geom._index;
2610         int newID = meshDS->ShapeToIndex( geom._shape );
2611         if ( oldID == 1 ) { // main shape
2612           newID = 1;
2613           geom._shape = newShape;
2614         }
2615         if ( !newID )
2616           continue;
2617         for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2618           _impl->AddHypothesis( geom._shape, (*hypIt)->GetID());
2619         // care of sub-meshes
2620         SMESH_subMesh* newSubmesh = _impl->GetSubMesh( geom._shape );
2621         if ( newID != oldID ) {
2622           _mapSubMesh   [ newID ] = newSubmesh;
2623           _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2624           _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2625           _mapSubMesh.   erase(oldID);
2626           _mapSubMesh_i. erase(oldID);
2627           _mapSubMeshIor.erase(oldID);
2628           _mapSubMesh_i [ newID ]->changeLocalId( newID );
2629         }
2630       }
2631       // recreate groups
2632       TShapeTypeList::iterator geomType = groupData.begin();
2633       for ( ; geomType != groupData.end(); ++geomType )
2634       {
2635         const TIndexedShape& geom = geomType->first;
2636         int oldID = geom._index;
2637         if ( _mapGroups.find( oldID ) == _mapGroups.end() )
2638           continue;
2639         // get group name
2640         SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( _mapGroups[oldID] );
2641         CORBA::String_var      name    = groupSO->GetName();
2642         // update
2643         if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>(_mapGroups[oldID]))
2644           if ( SMESH_Group* group = _impl->AddGroup( geomType->second, name.in(),
2645                                                      /*id=*/-1, geom._shape ))
2646             group_i->changeLocalId( group->GetID() );
2647       }
2648
2649       break; // everything has been updated
2650
2651     } // update mesh
2652   } // loop on group data
2653
2654   // Update icons
2655
2656   CORBA::Long newNbEntities = NbNodes() + NbElements();
2657   list< SALOMEDS::SObject_wrap > soToUpdateIcons;
2658   if ( newNbEntities != nbEntities )
2659   {
2660     // Add all SObjects with icons to soToUpdateIcons
2661     soToUpdateIcons.push_back( _gen_i->ObjectToSObject( _this() )); // mesh
2662
2663     for (map<int, SMESH::SMESH_subMesh_ptr>::iterator i_sm = _mapSubMeshIor.begin();
2664          i_sm != _mapSubMeshIor.end(); ++i_sm ) // submeshes
2665       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( i_sm->second ));
2666
2667     for ( map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
2668           i_gr != _mapGroups.end(); ++i_gr ) // groups
2669       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( i_gr->second ));
2670   }
2671
2672   list< SALOMEDS::SObject_wrap >::iterator so = soToUpdateIcons.begin();
2673   for ( ; so != soToUpdateIcons.end(); ++so )
2674     _gen_i->SetPixMap( *so, "ICON_SMESH_TREE_MESH_WARN" );
2675 }
2676
2677 //=============================================================================
2678 /*!
2679  * \brief Create standalone group from a group on geometry or filter
2680  */
2681 //=============================================================================
2682
2683 SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupBase_ptr theGroup )
2684   throw (SALOME::SALOME_Exception)
2685 {
2686   SMESH::SMESH_Group_var aGroup;
2687
2688   SMESH_TRY;
2689
2690   if ( _preMeshInfo )
2691     _preMeshInfo->FullLoadFromFile();
2692
2693   if ( theGroup->_is_nil() )
2694     return aGroup._retn();
2695
2696   SMESH_GroupBase_i* aGroupToRem = SMESH::DownCast<SMESH_GroupBase_i*>( theGroup );
2697   if ( !aGroupToRem )
2698     return aGroup._retn();
2699
2700   const bool isOnFilter = ( SMESH::DownCast< SMESH_GroupOnFilter_i* > ( theGroup ));
2701
2702   const int anId = aGroupToRem->GetLocalID();
2703   if ( !_impl->ConvertToStandalone( anId ) )
2704     return aGroup._retn();
2705   removeGeomGroupData( theGroup );
2706
2707   SMESH_GroupBase_i* aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
2708
2709   // remove old instance of group from own map
2710   { SMESH::SMESH_GroupBase_var var( _mapGroups[anId] ); } // decref CORBA object
2711   _mapGroups.erase( anId );
2712
2713   SALOMEDS::StudyBuilder_var builder;
2714   SALOMEDS::SObject_wrap     aGroupSO;
2715   SALOMEDS::Study_var        aStudy = SMESH_Gen_i::getStudyServant();
2716   if ( !aStudy->_is_nil() ) {
2717     builder  = aStudy->NewBuilder();
2718     aGroupSO = _gen_i->ObjectToSObject( theGroup );
2719     if ( !aGroupSO->_is_nil() )
2720     {
2721       // remove reference to geometry
2722       SALOMEDS::ChildIterator_wrap chItr = aStudy->NewChildIterator(aGroupSO);
2723       for ( ; chItr->More(); chItr->Next() )
2724       {
2725         // Remove group's child SObject
2726         SALOMEDS::SObject_wrap so = chItr->Value();
2727         builder->RemoveObject( so );
2728       }
2729       // Update Python script
2730       TPythonDump() << aGroupSO << " = " << SMESH::SMESH_Mesh_var(_this())
2731                     << ".ConvertToStandalone( " << aGroupSO << " )";
2732
2733       // change icon of Group on Filter
2734       if ( isOnFilter )
2735       {
2736         // SMESH::array_of_ElementType_var elemTypes = aGroupImpl->GetTypes();
2737         // const int isEmpty = ( elemTypes->length() == 0 );
2738         // if ( !isEmpty )
2739         {
2740           SALOMEDS::GenericAttribute_wrap anAttr =
2741             builder->FindOrCreateAttribute( aGroupSO, "AttributePixMap" );
2742           SALOMEDS::AttributePixMap_wrap pm = anAttr;
2743           pm->SetPixMap( "ICON_SMESH_TREE_GROUP" );
2744         }
2745       }
2746     }
2747   }
2748
2749   // remember new group in own map
2750   aGroup = SMESH::SMESH_Group::_narrow( aGroupImpl->_this() );
2751   _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
2752
2753   // register CORBA object for persistence
2754   _gen_i->RegisterObject( aGroup );
2755
2756   CORBA::String_var ior = _gen_i->GetORB()->object_to_string( aGroup );
2757   builder->SetIOR( aGroupSO, ior.in() ); //  == aGroup->Register();
2758   //aGroup->Register();
2759   aGroupToRem->UnRegister();
2760
2761   SMESH_CATCH( SMESH::throwCorbaException );
2762
2763   return aGroup._retn();
2764 }
2765
2766 //=============================================================================
2767 /*!
2768  *
2769  */
2770 //=============================================================================
2771
2772 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::createSubMesh( GEOM::GEOM_Object_ptr theSubShapeObject )
2773 {
2774   if(MYDEBUG) MESSAGE( "createSubMesh" );
2775   TopoDS_Shape  myLocSubShape = _gen_i->GeomObjectToShape(theSubShapeObject);
2776   ::SMESH_subMesh * mySubMesh = _impl->GetSubMesh(myLocSubShape);
2777   int               subMeshId = 0;
2778
2779   SMESH_subMesh_i * subMeshServant;
2780   if ( mySubMesh )
2781   {
2782     subMeshId = mySubMesh->GetId();
2783     subMeshServant = new SMESH_subMesh_i(myPOA, _gen_i, this, subMeshId);
2784   }
2785   else // "invalid sub-mesh"
2786   {
2787     // The invalid sub-mesh is created for the case where a valid sub-shape not found
2788     // by SMESH_Gen_i::CopyMeshWithGeom(). The invalid sub-mesh has GetId() < 0.
2789     if ( _mapSubMesh.empty() )
2790       subMeshId = -1;
2791     else
2792       subMeshId = _mapSubMesh.begin()->first - 1;
2793     subMeshServant = new SMESH_Invalid_subMesh_i(myPOA, _gen_i, this, subMeshId, theSubShapeObject);
2794   }
2795
2796   SMESH::SMESH_subMesh_var subMesh = subMeshServant->_this();
2797
2798   _mapSubMesh   [subMeshId] = mySubMesh;
2799   _mapSubMesh_i [subMeshId] = subMeshServant;
2800   _mapSubMeshIor[subMeshId] = SMESH::SMESH_subMesh::_duplicate( subMesh );
2801
2802   subMeshServant->Register();
2803
2804   // register CORBA object for persistence
2805   int nextId = _gen_i->RegisterObject( subMesh );
2806   if(MYDEBUG) { MESSAGE( "Add submesh to map with id = "<< nextId); }
2807   else        { nextId = 0; } // avoid "unused variable" warning
2808
2809   // to track changes of GEOM groups
2810   if ( subMeshId > 0 )
2811     addGeomGroupData( theSubShapeObject, subMesh );
2812
2813   return subMesh._retn();
2814 }
2815
2816 //=======================================================================
2817 //function : getSubMesh
2818 //purpose  :
2819 //=======================================================================
2820
2821 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::getSubMesh(int shapeID)
2822 {
2823   map<int, SMESH::SMESH_subMesh_ptr>::iterator it = _mapSubMeshIor.find( shapeID );
2824   if ( it == _mapSubMeshIor.end() )
2825     return SMESH::SMESH_subMesh::_nil();
2826
2827   return SMESH::SMESH_subMesh::_duplicate( (*it).second );
2828 }
2829
2830 //=============================================================================
2831 /*!
2832  *
2833  */
2834 //=============================================================================
2835
2836 bool SMESH_Mesh_i::removeSubMesh (SMESH::SMESH_subMesh_ptr theSubMesh,
2837                                   GEOM::GEOM_Object_ptr    theSubShapeObject )
2838 {
2839   bool isHypChanged = false;
2840   if ( theSubMesh->_is_nil() /*|| theSubShapeObject->_is_nil()*/ )
2841     return isHypChanged;
2842
2843   const int subMeshId = theSubMesh->GetId();
2844
2845   if ( theSubShapeObject->_is_nil() )  // not published shape (IPAL13617)
2846   {
2847     SMESH_subMesh* sm;
2848     if (( _mapSubMesh.count( subMeshId )) &&
2849         ( sm = _impl->GetSubMeshContaining( subMeshId )))
2850     {
2851       TopoDS_Shape S = sm->GetSubShape();
2852       if ( !S.IsNull() )
2853       {
2854         list<const SMESHDS_Hypothesis*> hyps = _impl->GetHypothesisList( S );
2855         isHypChanged = !hyps.empty();
2856         if ( isHypChanged && _preMeshInfo )
2857           _preMeshInfo->ForgetOrLoad();
2858         list<const SMESHDS_Hypothesis*>::const_iterator hyp = hyps.begin();
2859         for ( ; hyp != hyps.end(); ++hyp )
2860           _impl->RemoveHypothesis(S, (*hyp)->GetID());
2861       }
2862     }
2863   }
2864   else
2865   {
2866     try {
2867       SMESH::ListOfHypothesis_var aHypList = GetHypothesisList( theSubShapeObject );
2868       isHypChanged = ( aHypList->length() > 0 );
2869       for ( int i = 0, n = aHypList->length(); i < n; i++ ) {
2870         removeHypothesis( theSubShapeObject, aHypList[i] );
2871       }
2872     }
2873     catch( const SALOME::SALOME_Exception& ) {
2874       INFOS("SMESH_Mesh_i::removeSubMesh(): exception caught!");
2875     }
2876     removeGeomGroupData( theSubShapeObject );
2877   }
2878
2879   // remove a servant
2880   std::map<int, SMESH_subMesh_i*>::iterator id_smi = _mapSubMesh_i.find( subMeshId );
2881   if ( id_smi != _mapSubMesh_i.end() )
2882     id_smi->second->UnRegister();
2883
2884   // remove a CORBA object
2885   std::map<int, SMESH::SMESH_subMesh_ptr>::iterator id_smptr = _mapSubMeshIor.find( subMeshId );
2886   if ( id_smptr != _mapSubMeshIor.end() )
2887     SMESH::SMESH_subMesh_var( id_smptr->second );
2888
2889   _mapSubMesh.erase(subMeshId);
2890   _mapSubMesh_i.erase(subMeshId);
2891   _mapSubMeshIor.erase(subMeshId);
2892
2893   return isHypChanged;
2894 }
2895
2896 //=============================================================================
2897 /*!
2898  *
2899  */
2900 //=============================================================================
2901
2902 SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType        theElemType,
2903                                                       const char*               theName,
2904                                                       const int                 theID,
2905                                                       const TopoDS_Shape&       theShape,
2906                                                       const SMESH_PredicatePtr& thePredicate )
2907 {
2908   std::string newName;
2909   if ( !theName || !theName[0] )
2910   {
2911     std::set< std::string > presentNames;
2912     std::map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator i_gr = _mapGroups.begin();
2913     for ( ; i_gr != _mapGroups.end(); ++i_gr )
2914     {
2915       CORBA::String_var name = i_gr->second->GetName();
2916       presentNames.insert( name.in() );
2917     }
2918     do {
2919       newName = "noname_Group_" + SMESH_Comment( presentNames.size() + 1 );
2920     } while ( !presentNames.insert( newName ).second );
2921     theName = newName.c_str();
2922   }
2923   SMESH::SMESH_GroupBase_var aGroup;
2924   if ( SMESH_Group* g = _impl->AddGroup( (SMDSAbs_ElementType)theElemType, theName,
2925                                          theID, theShape, thePredicate ))
2926   {
2927     int anId = g->GetID();
2928     SMESH_GroupBase_i* aGroupImpl;
2929     if ( !theShape.IsNull() )
2930       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
2931     else if ( thePredicate )
2932       aGroupImpl = new SMESH_GroupOnFilter_i( SMESH_Gen_i::GetPOA(), this, anId );
2933     else
2934       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
2935
2936     aGroup = aGroupImpl->_this();
2937     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
2938     aGroupImpl->Register();
2939
2940     // register CORBA object for persistence
2941     int nextId = _gen_i->RegisterObject( aGroup );
2942     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
2943     else        { nextId = ( nextId > 0 ); } // avoid "unused variable" warning in release mode
2944
2945     // to track changes of GEOM groups
2946     if ( !theShape.IsNull() ) {
2947       GEOM::GEOM_Object_var geom = _gen_i->ShapeToGeomObject( theShape );
2948       addGeomGroupData( geom, aGroup );
2949     }
2950   }
2951   return aGroup._retn();
2952 }
2953
2954 //=============================================================================
2955 /*!
2956  * SMESH_Mesh_i::removeGroup
2957  *
2958  * Should be called by ~SMESH_Group_i()
2959  */
2960 //=============================================================================
2961
2962 void SMESH_Mesh_i::removeGroup( const int theId )
2963 {
2964   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::removeGroup()" );
2965   if ( _mapGroups.find( theId ) != _mapGroups.end() ) {
2966     SMESH::SMESH_GroupBase_var group = _mapGroups[theId];
2967     _mapGroups.erase( theId );
2968     removeGeomGroupData( group );
2969     if ( !_impl->RemoveGroup( theId ))
2970     {
2971       // it seems to be a call up from _impl caused by hyp modification (issue 0020918)
2972       RemoveGroup( group );
2973     }
2974     group->UnRegister();
2975   }
2976 }
2977
2978 //=============================================================================
2979 /*!
2980  *
2981  */
2982 //=============================================================================
2983
2984 SMESH::log_array * SMESH_Mesh_i::GetLog(CORBA::Boolean clearAfterGet)
2985   throw(SALOME::SALOME_Exception)
2986 {
2987   SMESH::log_array_var aLog;
2988
2989   SMESH_TRY;
2990   if ( _preMeshInfo )
2991     _preMeshInfo->FullLoadFromFile();
2992
2993   list < SMESHDS_Command * >logDS = _impl->GetLog();
2994   aLog = new SMESH::log_array;
2995   int indexLog = 0;
2996   int lg = logDS.size();
2997   SCRUTE(lg);
2998   aLog->length(lg);
2999   list < SMESHDS_Command * >::iterator its = logDS.begin();
3000   while(its != logDS.end()){
3001     SMESHDS_Command *com = *its;
3002     int comType = com->GetType();
3003     //SCRUTE(comType);
3004     int lgcom = com->GetNumber();
3005     //SCRUTE(lgcom);
3006     const list < int >&intList = com->GetIndexes();
3007     int inum = intList.size();
3008     //SCRUTE(inum);
3009     list < int >::const_iterator ii = intList.begin();
3010     const list < double >&coordList = com->GetCoords();
3011     int rnum = coordList.size();
3012     //SCRUTE(rnum);
3013     list < double >::const_iterator ir = coordList.begin();
3014     aLog[indexLog].commandType = comType;
3015     aLog[indexLog].number = lgcom;
3016     aLog[indexLog].coords.length(rnum);
3017     aLog[indexLog].indexes.length(inum);
3018     for(int i = 0; i < rnum; i++){
3019       aLog[indexLog].coords[i] = *ir;
3020       //MESSAGE(" "<<i<<" "<<ir.Value());
3021       ir++;
3022     }
3023     for(int i = 0; i < inum; i++){
3024       aLog[indexLog].indexes[i] = *ii;
3025       //MESSAGE(" "<<i<<" "<<ii.Value());
3026       ii++;
3027     }
3028     indexLog++;
3029     its++;
3030   }
3031   if(clearAfterGet)
3032     _impl->ClearLog();
3033
3034   SMESH_CATCH( SMESH::throwCorbaException );
3035
3036   return aLog._retn();
3037 }
3038
3039
3040 //=============================================================================
3041 /*!
3042  *
3043  */
3044 //=============================================================================
3045
3046 void SMESH_Mesh_i::ClearLog() throw(SALOME::SALOME_Exception)
3047 {
3048   SMESH_TRY;
3049   _impl->ClearLog();
3050   SMESH_CATCH( SMESH::throwCorbaException );
3051 }
3052
3053 //=============================================================================
3054 /*!
3055  *
3056  */
3057 //=============================================================================
3058
3059 CORBA::Long SMESH_Mesh_i::GetId()throw(SALOME::SALOME_Exception)
3060 {
3061   return _id;
3062 }
3063
3064 //=============================================================================
3065 namespace
3066 {
3067   //!< implementation of struct used to call methods of SMESH_Mesh_i from SMESH_Mesh
3068   // issue 0020918: groups removal is caused by hyp modification
3069   // issue 0021208: to forget not loaded mesh data at hyp modification
3070   struct TCallUp_i : public SMESH_Mesh::TCallUp
3071   {
3072     SMESH_Mesh_i* _mesh;
3073     TCallUp_i(SMESH_Mesh_i* mesh):_mesh(mesh) {}
3074     virtual void RemoveGroup (const int theGroupID) { _mesh->removeGroup( theGroupID ); }
3075     virtual void HypothesisModified (int theHypID)  { _mesh->onHypothesisModified( theHypID ); }
3076     virtual void Load ()                            { _mesh->Load(); }
3077   };
3078 }
3079
3080 //================================================================================
3081 /*!
3082  * \brief callback from _impl to forget not loaded mesh data (issue 0021208)
3083  */
3084 //================================================================================
3085
3086 void SMESH_Mesh_i::onHypothesisModified(int theHypID)
3087 {
3088   if ( _preMeshInfo )
3089     _preMeshInfo->ForgetOrLoad();
3090
3091   SMESH::SMESH_Mesh_var mesh = _this();
3092   _gen_i->UpdateIcons( mesh );
3093
3094   // mark a hypothesis as valid after edition
3095   SALOMEDS::SComponent_wrap smeshComp = _gen_i->PublishComponent();
3096   SALOMEDS::SObject_wrap hypRoot;
3097   if ( !smeshComp->_is_nil() && 
3098        smeshComp->FindSubObject( _gen_i->GetHypothesisRootTag(), hypRoot.inout() ))
3099   {
3100     SALOMEDS::ChildIterator_wrap anIter = _gen_i->getStudyServant()->NewChildIterator( hypRoot );
3101     for ( ; anIter->More(); anIter->Next() )
3102     {
3103       SALOMEDS::SObject_wrap    hypSO = anIter->Value();
3104       CORBA::Object_var           obj = _gen_i->SObjectToObject( hypSO );
3105       SMESH::SMESH_Hypothesis_var hyp = SMESH::SMESH_Hypothesis::_narrow( obj );
3106       if ( !hyp->_is_nil() && hyp->GetId() == theHypID )
3107         _gen_i->HighLightInvalid( hyp, false );
3108     }
3109   }
3110 }
3111
3112 //=============================================================================
3113 /*!
3114  *
3115  */
3116 //=============================================================================
3117
3118 void SMESH_Mesh_i::SetImpl(::SMESH_Mesh * impl)
3119 {
3120   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::SetImpl");
3121   _impl = impl;
3122   if ( _impl )
3123     _impl->SetCallUp( new TCallUp_i(this));
3124 }
3125
3126 //=============================================================================
3127 /*!
3128  *
3129  */
3130 //=============================================================================
3131
3132 ::SMESH_Mesh & SMESH_Mesh_i::GetImpl()
3133 {
3134   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::GetImpl()");
3135   return *_impl;
3136 }
3137
3138 //=============================================================================
3139 /*!
3140  * Return mesh editor
3141  */
3142 //=============================================================================
3143
3144 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditor()
3145   throw (SALOME::SALOME_Exception)
3146 {
3147   SMESH::SMESH_MeshEditor_var aMeshEdVar;
3148
3149   SMESH_TRY;
3150   if ( _preMeshInfo )
3151     _preMeshInfo->FullLoadFromFile();
3152
3153   // Create MeshEditor
3154   if ( !_editor )
3155     _editor = new SMESH_MeshEditor_i( this, false );
3156   aMeshEdVar = _editor->_this();
3157
3158   // Update Python script
3159   TPythonDump() << _editor << " = "
3160                 << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshEditor()";
3161
3162   SMESH_CATCH( SMESH::throwCorbaException );
3163
3164   return aMeshEdVar._retn();
3165 }
3166
3167 //=============================================================================
3168 /*!
3169  * Return mesh edition previewer
3170  */
3171 //=============================================================================
3172
3173 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditPreviewer()
3174   throw (SALOME::SALOME_Exception)
3175 {
3176   SMESH::SMESH_MeshEditor_var aMeshEdVar;
3177
3178   SMESH_TRY;
3179   if ( _preMeshInfo )
3180     _preMeshInfo->FullLoadFromFile();
3181
3182   if ( !_previewEditor )
3183     _previewEditor = new SMESH_MeshEditor_i( this, true );
3184   aMeshEdVar = _previewEditor->_this();
3185
3186   SMESH_CATCH( SMESH::throwCorbaException );
3187
3188   return aMeshEdVar._retn();
3189 }
3190
3191 //================================================================================
3192 /*!
3193  * \brief Return true if the mesh has been edited since a last total re-compute
3194  *        and those modifications may prevent successful partial re-compute
3195  */
3196 //================================================================================
3197
3198 CORBA::Boolean SMESH_Mesh_i::HasModificationsToDiscard() throw(SALOME::SALOME_Exception)
3199 {
3200   Unexpect aCatch(SALOME_SalomeException);
3201   return _impl->HasModificationsToDiscard();
3202 }
3203
3204 //================================================================================
3205 /*!
3206  * \brief Returns a random unique color
3207  */
3208 //================================================================================
3209
3210 static SALOMEDS::Color getUniqueColor( const std::list<SALOMEDS::Color>& theReservedColors )
3211 {