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