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