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