Salome HOME
Merge from BR_WIN_INDUS_514 04/10/2010
[modules/smesh.git] / src / SMESH_I / SMESH_Mesh_i.cxx
1 //  Copyright (C) 2007-2010  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.
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 //  SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses
23 //  File   : SMESH_Mesh_i.cxx
24 //  Author : Paul RASCLE, EDF
25 //  Module : SMESH
26
27 #include "SMESH_Mesh_i.hxx"
28
29 #include "SMESH_Filter_i.hxx"
30 #include "SMESH_Gen_i.hxx"
31 #include "SMESH_Group_i.hxx"
32 #include "SMESH_MEDMesh_i.hxx"
33 #include "SMESH_MeshEditor_i.hxx"
34 #include "SMESH_PythonDump.hxx"
35 #include "SMESH_subMesh_i.hxx"
36
37 #include "DriverMED_R_SMESHDS_Mesh.h"
38 #include "DriverMED_W_SMESHDS_Mesh.h"
39 #include "SMDS_VolumeTool.hxx"
40 #include "SMDS_ElemIterator.hxx"
41 #include "SMESHDS_Command.hxx"
42 #include "SMESHDS_CommandType.hxx"
43 #include "SMESHDS_GroupOnGeom.hxx"
44 #include "SMESH_Group.hxx"
45 #include "SMESH_MeshEditor.hxx"
46 #include "SMESH_MesherHelper.hxx"
47 #include "SMDS_EdgePosition.hxx"
48 #include "SMDS_FacePosition.hxx"
49
50 #include "OpUtil.hxx"
51 #include "SALOME_NamingService.hxx"
52 #include "Utils_CorbaException.hxx"
53 #include "Utils_ExceptHandlers.hxx"
54 #include "Utils_SINGLETON.hxx"
55 #include "utilities.h"
56 #include "GEOMImpl_Types.hxx"
57
58 // OCCT Includes
59 #include <BRep_Builder.hxx>
60 #include <OSD_Directory.hxx>
61 #include <OSD_File.hxx>
62 #include <OSD_Path.hxx>
63 #include <OSD_Protection.hxx>
64 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
65 #include <TColStd_MapOfInteger.hxx>
66 #include <TColStd_SequenceOfInteger.hxx>
67 #include <TCollection_AsciiString.hxx>
68 #include <TopExp.hxx>
69 #include <TopExp_Explorer.hxx>
70 #include <TopoDS_Compound.hxx>
71 #include <TopTools_MapOfShape.hxx>
72 #include <TopTools_MapIteratorOfMapOfShape.hxx>
73
74 // STL Includes
75 #include <algorithm>
76 #include <string>
77 #include <iostream>
78 #include <sstream>
79 #include <sys/stat.h>
80
81 #ifdef _DEBUG_
82 static int MYDEBUG = 0;
83 #else
84 static int MYDEBUG = 0;
85 #endif
86
87 using namespace std;
88 using SMESH::TPythonDump;
89
90 int SMESH_Mesh_i::myIdGenerator = 0;
91
92 //To disable automatic genericobj management, the following line should be commented.
93 //Otherwise, it should be uncommented. Refer to KERNEL_SRC/src/SALOMEDSImpl/SALOMEDSImpl_AttributeIOR.cxx
94 #define WITHGENERICOBJ
95
96 //=============================================================================
97 /*!
98  *  Constructor
99  */
100 //=============================================================================
101
102 SMESH_Mesh_i::SMESH_Mesh_i( PortableServer::POA_ptr thePOA,
103                             SMESH_Gen_i*            gen_i,
104                             CORBA::Long studyId )
105 : SALOME::GenericObj_i( thePOA )
106 {
107   MESSAGE("SMESH_Mesh_i");
108   _impl = NULL;
109   _gen_i = gen_i;
110   _id = myIdGenerator++;
111   _studyId = studyId;
112 }
113
114 //=============================================================================
115 /*!
116  *  Destructor
117  */
118 //=============================================================================
119
120 SMESH_Mesh_i::~SMESH_Mesh_i()
121 {
122   INFOS("~SMESH_Mesh_i");
123
124 #ifdef WITHGENERICOBJ
125   // destroy groups
126   map<int, SMESH::SMESH_GroupBase_ptr>::iterator itGr;
127   for (itGr = _mapGroups.begin(); itGr != _mapGroups.end(); itGr++) {
128     if ( CORBA::is_nil( itGr->second ))
129       continue;
130     SMESH_GroupBase_i* aGroup = dynamic_cast<SMESH_GroupBase_i*>(SMESH_Gen_i::GetServant(itGr->second).in());
131     if (aGroup) {
132       // this method is called from destructor of group (PAL6331)
133       //_impl->RemoveGroup( aGroup->GetLocalID() );
134       aGroup->myMeshServant = 0;
135       aGroup->Destroy();
136     }
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 ( CORBA::is_nil( itSM->second ))
144       continue;
145     SMESH_subMesh_i* aSubMesh = dynamic_cast<SMESH_subMesh_i*>(SMESH_Gen_i::GetServant(itSM->second).in());
146     if (aSubMesh) {
147       aSubMesh->Destroy();
148     }
149   }
150   _mapSubMeshIor.clear();
151
152   // destroy hypotheses
153   map<int, SMESH::SMESH_Hypothesis_ptr>::iterator itH;
154   for ( itH = _mapHypo.begin(); itH != _mapHypo.end(); itH++ ) {
155     if ( CORBA::is_nil( itH->second ))
156       continue;
157     SMESH_Hypothesis_i* aHypo = dynamic_cast<SMESH_Hypothesis_i*>(SMESH_Gen_i::GetServant(itH->second).in());
158     if (aHypo) {
159       aHypo->Destroy();
160     }
161   }
162   _mapHypo.clear();
163 #endif
164
165   delete _impl;
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   addGeomGroupData( theShapeObject, _this() );
190 }
191
192 //================================================================================
193 /*!
194  * \brief return true if mesh has a shape to build a shape on
195  */
196 //================================================================================
197
198 CORBA::Boolean SMESH_Mesh_i::HasShapeToMesh()
199   throw (SALOME::SALOME_Exception)
200 {
201   Unexpect aCatch(SALOME_SalomeException);
202   bool res = false;
203   try {
204     res = _impl->HasShapeToMesh();
205   }
206   catch(SALOME_Exception & S_ex) {
207     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
208   }
209   return res;
210 }
211
212 //=======================================================================
213 //function : GetShapeToMesh
214 //purpose  :
215 //=======================================================================
216
217 GEOM::GEOM_Object_ptr SMESH_Mesh_i::GetShapeToMesh()
218   throw (SALOME::SALOME_Exception)
219 {
220   Unexpect aCatch(SALOME_SalomeException);
221   GEOM::GEOM_Object_var aShapeObj;
222   try {
223     TopoDS_Shape S = _impl->GetMeshDS()->ShapeToMesh();
224     if ( !S.IsNull() )
225       aShapeObj = _gen_i->ShapeToGeomObject( S );
226   }
227   catch(SALOME_Exception & S_ex) {
228     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
229   }
230   return aShapeObj._retn();
231 }
232
233 //================================================================================
234 /*!
235  * \brief Remove all nodes and elements
236  */
237 //================================================================================
238
239 void SMESH_Mesh_i::Clear() throw (SALOME::SALOME_Exception)
240 {
241   Unexpect aCatch(SALOME_SalomeException);
242   try {
243     _impl->Clear();
244     CheckGeomGroupModif(); // issue 20145
245   }
246   catch(SALOME_Exception & S_ex) {
247     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
248   }
249   TPythonDump() <<  _this() << ".Clear()";
250 }
251
252 //================================================================================
253 /*!
254  * \brief Remove all nodes and elements for indicated shape
255  */
256 //================================================================================
257
258 void SMESH_Mesh_i::ClearSubMesh(CORBA::Long ShapeID)
259   throw (SALOME::SALOME_Exception)
260 {
261   Unexpect aCatch(SALOME_SalomeException);
262   try {
263     _impl->ClearSubMesh( ShapeID );
264   }
265   catch(SALOME_Exception & S_ex) {
266     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
267   }
268 }
269
270 //=============================================================================
271 /*!
272  *
273  */
274 //=============================================================================
275
276 static SMESH::DriverMED_ReadStatus ConvertDriverMEDReadStatus (int theStatus)
277 {
278   SMESH::DriverMED_ReadStatus res;
279   switch (theStatus)
280   {
281   case DriverMED_R_SMESHDS_Mesh::DRS_OK:
282     res = SMESH::DRS_OK; break;
283   case DriverMED_R_SMESHDS_Mesh::DRS_EMPTY:
284     res = SMESH::DRS_EMPTY; break;
285   case DriverMED_R_SMESHDS_Mesh::DRS_WARN_RENUMBER:
286     res = SMESH::DRS_WARN_RENUMBER; break;
287   case DriverMED_R_SMESHDS_Mesh::DRS_WARN_SKIP_ELEM:
288     res = SMESH::DRS_WARN_SKIP_ELEM; break;
289   case DriverMED_R_SMESHDS_Mesh::DRS_FAIL:
290   default:
291     res = SMESH::DRS_FAIL; break;
292   }
293   return res;
294 }
295
296 //=============================================================================
297 /*!
298  *  ImportMEDFile
299  *
300  *  Imports mesh data from MED file
301  */
302 //=============================================================================
303
304 SMESH::DriverMED_ReadStatus
305 SMESH_Mesh_i::ImportMEDFile( const char* theFileName, const char* theMeshName )
306   throw ( SALOME::SALOME_Exception )
307 {
308   Unexpect aCatch(SALOME_SalomeException);
309   int status;
310   try {
311     status = _impl->MEDToMesh( theFileName, theMeshName );
312   }
313   catch( SALOME_Exception& S_ex ) {
314     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
315   }
316   catch ( ... ) {
317     THROW_SALOME_CORBA_EXCEPTION("ImportMEDFile(): unknown exception", SALOME::BAD_PARAM);
318   }
319
320   CreateGroupServants();
321
322   int major, minor, release;
323   if( !MED::getMEDVersion( theFileName, major, minor, release ) )
324     major = minor = release = -1;
325   myFileInfo           = new SALOME_MED::MedFileInfo();
326   myFileInfo->fileName = theFileName;
327   myFileInfo->fileSize = 0;
328 #ifdef WIN32
329   struct _stati64 d;
330   if ( ::_stati64( theFileName, &d ) != -1 )
331 #else
332   struct stat64 d;
333   if ( ::stat64( theFileName, &d ) != -1 )
334 #endif
335     myFileInfo->fileSize = d.st_size;
336   myFileInfo->major    = major;
337   myFileInfo->minor    = minor;
338   myFileInfo->release  = release;
339
340   return ConvertDriverMEDReadStatus(status);
341 }
342
343 //================================================================================
344 /*!
345  * \brief Return string representation of a MED file version comprising nbDigits
346  */
347 //================================================================================
348
349 char* SMESH_Mesh_i::GetVersionString(SMESH::MED_VERSION version, CORBA::Short nbDigits)
350 {
351   string ver = DriverMED_W_SMESHDS_Mesh::GetVersionString(MED::EVersion(version),
352                                                                nbDigits);
353   return CORBA::string_dup( ver.c_str() );
354 }
355
356 //=============================================================================
357 /*!
358  *  ImportUNVFile
359  *
360  *  Imports mesh data from MED file
361  */
362 //=============================================================================
363
364 int SMESH_Mesh_i::ImportUNVFile( const char* theFileName )
365   throw ( SALOME::SALOME_Exception )
366 {
367   // Read mesh with name = <theMeshName> into SMESH_Mesh
368   _impl->UNVToMesh( theFileName );
369
370   CreateGroupServants();
371
372   return 1;
373 }
374
375 //=============================================================================
376 /*!
377  *  ImportSTLFile
378  *
379  *  Imports mesh data from STL file
380  */
381 //=============================================================================
382 int SMESH_Mesh_i::ImportSTLFile( const char* theFileName )
383   throw ( SALOME::SALOME_Exception )
384 {
385   // Read mesh with name = <theMeshName> into SMESH_Mesh
386   _impl->STLToMesh( theFileName );
387
388   return 1;
389 }
390
391 //=============================================================================
392 /*!
393  *  importMEDFile
394  *
395  *  Imports mesh data from MED file
396  */
397 //=============================================================================
398
399 // int SMESH_Mesh_i::importMEDFile( const char* theFileName, const char* theMeshName )
400 // {
401 //   // Read mesh with name = <theMeshName> and all its groups into SMESH_Mesh
402 //   int status = _impl->MEDToMesh( theFileName, theMeshName );
403 //   CreateGroupServants();
404
405 //   return status;
406 // }
407
408 //=============================================================================
409 /*!
410  *
411  */
412 //=============================================================================
413
414 #define RETURNCASE(hyp_stat) case SMESH_Hypothesis::hyp_stat: return SMESH::hyp_stat;
415
416 SMESH::Hypothesis_Status SMESH_Mesh_i::ConvertHypothesisStatus
417                          (SMESH_Hypothesis::Hypothesis_Status theStatus)
418 {
419   switch (theStatus) {
420   RETURNCASE( HYP_OK            );
421   RETURNCASE( HYP_MISSING       );
422   RETURNCASE( HYP_CONCURENT     );
423   RETURNCASE( HYP_BAD_PARAMETER );
424   RETURNCASE( HYP_HIDDEN_ALGO   );
425   RETURNCASE( HYP_HIDING_ALGO   );
426   RETURNCASE( HYP_UNKNOWN_FATAL );
427   RETURNCASE( HYP_INCOMPATIBLE  );
428   RETURNCASE( HYP_NOTCONFORM    );
429   RETURNCASE( HYP_ALREADY_EXIST );
430   RETURNCASE( HYP_BAD_DIM       );
431   RETURNCASE( HYP_BAD_SUBSHAPE  );
432   RETURNCASE( HYP_BAD_GEOMETRY  );
433   RETURNCASE( HYP_NEED_SHAPE    );
434   default:;
435   }
436   return SMESH::HYP_UNKNOWN_FATAL;
437 }
438
439 //=============================================================================
440 /*!
441  *  AddHypothesis
442  *
443  *  calls internal addHypothesis() and then adds a reference to <anHyp> under
444  *  the SObject actually having a reference to <aSubShape>.
445  *  NB: For this method to work, it is necessary to add a reference to sub-shape first.
446  */
447 //=============================================================================
448
449 SMESH::Hypothesis_Status SMESH_Mesh_i::AddHypothesis(GEOM::GEOM_Object_ptr aSubShapeObject,
450                                                      SMESH::SMESH_Hypothesis_ptr anHyp)
451   throw(SALOME::SALOME_Exception)
452 {
453   Unexpect aCatch(SALOME_SalomeException);
454   SMESH_Hypothesis::Hypothesis_Status status = addHypothesis( aSubShapeObject, anHyp );
455
456   if ( !SMESH_Hypothesis::IsStatusFatal(status) )
457     _gen_i->AddHypothesisToShape(_gen_i->GetCurrentStudy(), _this(),
458                                  aSubShapeObject, anHyp );
459
460   if(MYDEBUG) MESSAGE( " AddHypothesis(): status = " << status );
461
462   // Update Python script
463   if(_impl->HasShapeToMesh()) {
464     TPythonDump() << "status = " << _this() << ".AddHypothesis( "
465                   << aSubShapeObject << ", " << anHyp << " )";
466   }
467   else {
468     TPythonDump() << "status = " << _this() << ".AddHypothesis( "<< anHyp << " )";
469   }
470   
471   return ConvertHypothesisStatus(status);
472 }
473
474 //=============================================================================
475 /*!
476  *
477  */
478 //=============================================================================
479
480 SMESH_Hypothesis::Hypothesis_Status
481   SMESH_Mesh_i::addHypothesis(GEOM::GEOM_Object_ptr       aSubShapeObject,
482                               SMESH::SMESH_Hypothesis_ptr anHyp)
483 {
484   if(MYDEBUG) MESSAGE("addHypothesis");
485
486   if (CORBA::is_nil(aSubShapeObject) && HasShapeToMesh())
487     THROW_SALOME_CORBA_EXCEPTION("bad subShape reference",
488                                  SALOME::BAD_PARAM);
489
490   SMESH::SMESH_Hypothesis_var myHyp = SMESH::SMESH_Hypothesis::_narrow(anHyp);
491   if (CORBA::is_nil(myHyp))
492     THROW_SALOME_CORBA_EXCEPTION("bad hypothesis reference",
493                                  SALOME::BAD_PARAM);
494
495   SMESH_Hypothesis::Hypothesis_Status status = SMESH_Hypothesis::HYP_OK;
496   try
497   {
498     TopoDS_Shape myLocSubShape;
499     //use PseudoShape in case if mesh has no shape
500     if(HasShapeToMesh())
501       myLocSubShape = _gen_i->GeomObjectToShape( aSubShapeObject);
502     else              
503       myLocSubShape = _impl->GetShapeToMesh();
504     
505     int hypId = myHyp->GetId();
506     status = _impl->AddHypothesis(myLocSubShape, hypId);
507     if ( !SMESH_Hypothesis::IsStatusFatal(status) ) {
508       _mapHypo[hypId] = SMESH::SMESH_Hypothesis::_duplicate( myHyp );
509 #ifdef WITHGENERICOBJ
510       _mapHypo[hypId]->Register();
511 #endif
512       // assure there is a corresponding submesh
513       if ( !_impl->IsMainShape( myLocSubShape )) {
514         int shapeId = _impl->GetMeshDS()->ShapeToIndex( myLocSubShape );
515         if ( _mapSubMesh_i.find( shapeId ) == _mapSubMesh_i.end() )
516           createSubMesh( aSubShapeObject );
517       }
518     }
519   }
520   catch(SALOME_Exception & S_ex)
521   {
522     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
523   }
524   return status;
525 }
526
527 //=============================================================================
528 /*!
529  *
530  */
531 //=============================================================================
532
533 SMESH::Hypothesis_Status SMESH_Mesh_i::RemoveHypothesis(GEOM::GEOM_Object_ptr aSubShapeObject,
534                                                         SMESH::SMESH_Hypothesis_ptr anHyp)
535      throw(SALOME::SALOME_Exception)
536 {
537   Unexpect aCatch(SALOME_SalomeException);
538   SMESH_Hypothesis::Hypothesis_Status status = removeHypothesis( aSubShapeObject, anHyp );
539
540   if ( !SMESH_Hypothesis::IsStatusFatal(status) )
541     _gen_i->RemoveHypothesisFromShape(_gen_i->GetCurrentStudy(), _this(),
542                                       aSubShapeObject, anHyp );
543
544   // Update Python script
545     // Update Python script
546   if(_impl->HasShapeToMesh()) {
547   TPythonDump() << "status = " << _this() << ".RemoveHypothesis( "
548                 << aSubShapeObject << ", " << anHyp << " )";
549   }
550   else {
551     TPythonDump() << "status = " << _this() << ".RemoveHypothesis( "
552                   << anHyp << " )";
553   }
554
555   return ConvertHypothesisStatus(status);
556 }
557
558 //=============================================================================
559 /*!
560  *
561  */
562 //=============================================================================
563
564 SMESH_Hypothesis::Hypothesis_Status
565 SMESH_Mesh_i::removeHypothesis(GEOM::GEOM_Object_ptr       aSubShapeObject,
566                                SMESH::SMESH_Hypothesis_ptr anHyp)
567 {
568   if(MYDEBUG) MESSAGE("removeHypothesis()");
569   // **** proposer liste de subShape (selection multiple)
570
571   if (CORBA::is_nil(aSubShapeObject) && HasShapeToMesh())
572     THROW_SALOME_CORBA_EXCEPTION("bad subShape reference", SALOME::BAD_PARAM);
573
574   SMESH::SMESH_Hypothesis_var myHyp = SMESH::SMESH_Hypothesis::_narrow(anHyp);
575   if (CORBA::is_nil(myHyp))
576     THROW_SALOME_CORBA_EXCEPTION("bad hypothesis reference", SALOME::BAD_PARAM);
577
578   SMESH_Hypothesis::Hypothesis_Status status = SMESH_Hypothesis::HYP_OK;
579   try
580   {
581     TopoDS_Shape myLocSubShape;
582     //use PseudoShape in case if mesh has no shape
583     if(HasShapeToMesh())
584       myLocSubShape = _gen_i->GeomObjectToShape( aSubShapeObject);
585     else
586       myLocSubShape = _impl->GetShapeToMesh();
587
588     int hypId = myHyp->GetId();
589     status = _impl->RemoveHypothesis(myLocSubShape, hypId);
590 //     if ( !SMESH_Hypothesis::IsStatusFatal(status) ) EAP: hyp can be used on many subshapes
591 //       _mapHypo.erase( hypId );
592   }
593   catch(SALOME_Exception & S_ex)
594   {
595     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
596   }
597   return status;
598 }
599
600 //=============================================================================
601 /*!
602  *
603  */
604 //=============================================================================
605
606 SMESH::ListOfHypothesis *
607         SMESH_Mesh_i::GetHypothesisList(GEOM::GEOM_Object_ptr aSubShapeObject)
608 throw(SALOME::SALOME_Exception)
609 {
610   Unexpect aCatch(SALOME_SalomeException);
611   if (MYDEBUG) MESSAGE("GetHypothesisList");
612   if (_impl->HasShapeToMesh() && CORBA::is_nil(aSubShapeObject))
613     THROW_SALOME_CORBA_EXCEPTION("bad subShape reference", SALOME::BAD_PARAM);
614
615   SMESH::ListOfHypothesis_var aList = new SMESH::ListOfHypothesis();
616
617   try {
618     TopoDS_Shape myLocSubShape = _gen_i->GeomObjectToShape(aSubShapeObject);
619     if ( myLocSubShape.IsNull() && !_impl->HasShapeToMesh() )
620       myLocSubShape = _impl->GetShapeToMesh();
621     const list<const SMESHDS_Hypothesis*>& aLocalList = _impl->GetHypothesisList( myLocSubShape );
622     int i = 0, n = aLocalList.size();
623     aList->length( n );
624
625     for ( list<const SMESHDS_Hypothesis*>::const_iterator anIt = aLocalList.begin(); i < n && anIt != aLocalList.end(); anIt++ ) {
626       SMESHDS_Hypothesis* aHyp = (SMESHDS_Hypothesis*)(*anIt);
627       if ( _mapHypo.find( aHyp->GetID() ) != _mapHypo.end() )
628         aList[i++] = SMESH::SMESH_Hypothesis::_narrow( _mapHypo[aHyp->GetID()] );
629     }
630
631     aList->length( i );
632   }
633   catch(SALOME_Exception & S_ex) {
634     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
635   }
636
637   return aList._retn();
638 }
639
640 //=============================================================================
641 /*!
642  *
643  */
644 //=============================================================================
645 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::GetSubMesh(GEOM::GEOM_Object_ptr aSubShapeObject,
646                                                   const char*           theName )
647      throw(SALOME::SALOME_Exception)
648 {
649   Unexpect aCatch(SALOME_SalomeException);
650   MESSAGE("SMESH_Mesh_i::GetSubMesh");
651   if (CORBA::is_nil(aSubShapeObject))
652     THROW_SALOME_CORBA_EXCEPTION("bad subShape reference",
653                                  SALOME::BAD_PARAM);
654
655   SMESH::SMESH_subMesh_var subMesh;
656   SMESH::SMESH_Mesh_var    aMesh = SMESH::SMESH_Mesh::_narrow(_this());
657   try {
658     TopoDS_Shape myLocSubShape = _gen_i->GeomObjectToShape(aSubShapeObject);
659
660     //Get or Create the SMESH_subMesh object implementation
661
662     int subMeshId = _impl->GetMeshDS()->ShapeToIndex( myLocSubShape );
663     if ( !subMeshId && ! _impl->GetMeshDS()->IsGroupOfSubShapes( myLocSubShape ))
664       THROW_SALOME_CORBA_EXCEPTION("not sub-shape of the main shape", SALOME::BAD_PARAM);
665
666     subMesh = getSubMesh( subMeshId );
667
668     // create a new subMesh object servant if there is none for the shape
669     if ( subMesh->_is_nil() )
670       subMesh = createSubMesh( aSubShapeObject );
671     if ( _gen_i->CanPublishInStudy( subMesh )) {
672       SALOMEDS::SObject_var aSO =
673         _gen_i->PublishSubMesh(_gen_i->GetCurrentStudy(), aMesh,
674                                subMesh, aSubShapeObject, theName );
675       if ( !aSO->_is_nil()) {
676         // Update Python script
677         TPythonDump() << aSO << " = " << _this() << ".GetSubMesh( "
678                       << aSubShapeObject << ", '" << theName << "' )";
679       }
680     }
681   }
682   catch(SALOME_Exception & S_ex) {
683     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
684   }
685   return subMesh._retn();
686 }
687
688 //=============================================================================
689 /*!
690  *
691  */
692 //=============================================================================
693
694 void SMESH_Mesh_i::RemoveSubMesh( SMESH::SMESH_subMesh_ptr theSubMesh )
695      throw (SALOME::SALOME_Exception)
696 {
697   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::RemoveSubMesh");
698   if ( theSubMesh->_is_nil() )
699     return;
700
701   GEOM::GEOM_Object_var aSubShapeObject;
702   SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy();
703   if ( !aStudy->_is_nil() )  {
704     // Remove submesh's SObject
705     SALOMEDS::SObject_var anSO = _gen_i->ObjectToSObject( aStudy, theSubMesh );
706     if ( !anSO->_is_nil() ) {
707       long aTag = SMESH_Gen_i::GetRefOnShapeTag();
708       SALOMEDS::SObject_var anObj, aRef;
709       if ( anSO->FindSubObject( aTag, anObj ) && anObj->ReferencedObject( aRef ) )
710         aSubShapeObject = GEOM::GEOM_Object::_narrow( aRef->GetObject() );
711
712 //       if ( aSubShapeObject->_is_nil() ) // not published shape (IPAL13617)
713 //         aSubShapeObject = theSubMesh->GetSubShape();
714
715       aStudy->NewBuilder()->RemoveObjectWithChildren( anSO );
716
717       // Update Python script
718       TPythonDump() << _this() << ".RemoveSubMesh( " << anSO << " )";
719     }
720   }
721
722   removeSubMesh( theSubMesh, aSubShapeObject.in() );
723 }
724
725 //=============================================================================
726 /*!
727  *  ElementTypeString
728  */
729 //=============================================================================
730 #define CASE2STRING(enum) case SMESH::enum: return "SMESH."#enum;
731 inline TCollection_AsciiString ElementTypeString (SMESH::ElementType theElemType)
732 {
733   switch (theElemType) {
734     CASE2STRING( ALL );
735     CASE2STRING( NODE );
736     CASE2STRING( EDGE );
737     CASE2STRING( FACE );
738     CASE2STRING( VOLUME );
739     CASE2STRING( ELEM0D );
740   default:;
741   }
742   return "";
743 }
744
745 //=============================================================================
746 /*!
747  *
748  */
749 //=============================================================================
750
751 SMESH::SMESH_Group_ptr SMESH_Mesh_i::CreateGroup( SMESH::ElementType theElemType,
752                                                  const char*         theName )
753      throw(SALOME::SALOME_Exception)
754 {
755   Unexpect aCatch(SALOME_SalomeException);
756   SMESH::SMESH_Group_var aNewGroup =
757     SMESH::SMESH_Group::_narrow( createGroup( theElemType, theName ));
758
759   if ( _gen_i->CanPublishInStudy( aNewGroup ) ) {
760     SALOMEDS::SObject_var aSO =
761       _gen_i->PublishGroup(_gen_i->GetCurrentStudy(), _this(),
762                            aNewGroup, GEOM::GEOM_Object::_nil(), theName);
763     if ( !aSO->_is_nil()) {
764       // Update Python script
765       TPythonDump() << aSO << " = " << _this() << ".CreateGroup( "
766                     << ElementTypeString(theElemType) << ", '" << theName << "' )";
767     }
768   }
769   return aNewGroup._retn();
770 }
771
772
773 //=============================================================================
774 /*!
775  *
776  */
777 //=============================================================================
778 SMESH::SMESH_GroupOnGeom_ptr SMESH_Mesh_i::CreateGroupFromGEOM (SMESH::ElementType    theElemType,
779                                                                 const char*           theName,
780                                                                 GEOM::GEOM_Object_ptr theGeomObj)
781      throw(SALOME::SALOME_Exception)
782 {
783   Unexpect aCatch(SALOME_SalomeException);
784   SMESH::SMESH_GroupOnGeom_var aNewGroup;
785
786   TopoDS_Shape aShape = _gen_i->GeomObjectToShape( theGeomObj );
787   if ( !aShape.IsNull() )
788   {
789     aNewGroup = SMESH::SMESH_GroupOnGeom::_narrow
790       ( createGroup( theElemType, theName, aShape ));
791
792     if ( _gen_i->CanPublishInStudy( aNewGroup ) ) {
793       SALOMEDS::SObject_var aSO =
794         _gen_i->PublishGroup(_gen_i->GetCurrentStudy(), _this(),
795                              aNewGroup, theGeomObj, theName);
796       if ( !aSO->_is_nil()) {
797         // Update Python script
798         TPythonDump() << aSO << " = " << _this() << ".CreateGroupFromGEOM("
799                       << ElementTypeString(theElemType) << ", '" << theName << "', "
800                       << theGeomObj << " )";
801       }
802     }
803   }
804
805   return aNewGroup._retn();
806 }
807
808 //=============================================================================
809 /*!
810  *
811  */
812 //=============================================================================
813
814 void SMESH_Mesh_i::RemoveGroup( SMESH::SMESH_GroupBase_ptr theGroup )
815      throw (SALOME::SALOME_Exception)
816 {
817   if ( theGroup->_is_nil() )
818     return;
819
820   SMESH_GroupBase_i* aGroup =
821     dynamic_cast<SMESH_GroupBase_i*>( SMESH_Gen_i::GetServant( theGroup ).in() );
822   if ( !aGroup )
823     return;
824
825   SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy();
826   if ( !aStudy->_is_nil() )  {
827     SALOMEDS::SObject_var aGroupSO = _gen_i->ObjectToSObject( aStudy, theGroup );
828
829     if ( !aGroupSO->_is_nil() ) {
830       // Update Python script
831       TPythonDump() << _this() << ".RemoveGroup( " << aGroupSO << " )";
832
833       // Remove group's SObject
834       aStudy->NewBuilder()->RemoveObjectWithChildren( aGroupSO );
835     }
836   }
837
838   // Remove the group from SMESH data structures
839   removeGroup( aGroup->GetLocalID() );
840 }
841
842 //=============================================================================
843 /*! RemoveGroupWithContents
844  *  Remove group with its contents
845  */
846 //=============================================================================
847 void SMESH_Mesh_i::RemoveGroupWithContents( SMESH::SMESH_GroupBase_ptr theGroup )
848   throw (SALOME::SALOME_Exception)
849 {
850   if ( theGroup->_is_nil() )
851     return;
852
853   SMESH_GroupBase_i* aGroup =
854     dynamic_cast<SMESH_GroupBase_i*>( SMESH_Gen_i::GetServant( theGroup ).in() );
855   if ( !aGroup )
856     return;
857
858   SMESH::long_array_var anIds = aGroup->GetListOfID();
859   SMESH::SMESH_MeshEditor_var aMeshEditor = SMESH_Mesh_i::GetMeshEditor();
860
861   // Update Python script
862   TPythonDump() << _this() << ".RemoveGroupWithContents( " << theGroup << " )";
863
864   // Remove contents
865   if ( aGroup->GetType() == SMESH::NODE )
866     aMeshEditor->RemoveNodes( anIds );
867   else
868     aMeshEditor->RemoveElements( anIds );
869
870   // Remove group
871   RemoveGroup( theGroup );
872
873   // Clear python lines, created by RemoveNodes/Elements() and RemoveGroup()
874   _gen_i->RemoveLastFromPythonScript(_gen_i->GetCurrentStudy()->StudyId());
875   _gen_i->RemoveLastFromPythonScript(_gen_i->GetCurrentStudy()->StudyId());
876 }
877
878
879 //================================================================================
880 /*!
881  * \brief Get the list of groups existing in the mesh
882   * \retval SMESH::ListOfGroups * - list of groups
883  */
884 //================================================================================
885
886 SMESH::ListOfGroups * SMESH_Mesh_i::GetGroups() throw(SALOME::SALOME_Exception)
887 {
888   Unexpect aCatch(SALOME_SalomeException);
889   if (MYDEBUG) MESSAGE("GetGroups");
890
891   SMESH::ListOfGroups_var aList = new SMESH::ListOfGroups();
892
893   // Python Dump
894   TPythonDump aPythonDump;
895   if ( !_mapGroups.empty() ) // (IMP13463) avoid "SyntaxError: can't assign to []"
896     aPythonDump << "[ ";
897
898   try {
899     aList->length( _mapGroups.size() );
900     int i = 0;
901     map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.begin();
902     for ( ; it != _mapGroups.end(); it++ ) {
903       if ( CORBA::is_nil( it->second )) continue;
904       aList[i++] = SMESH::SMESH_GroupBase::_duplicate( it->second );
905       // Python Dump
906       if (i > 1) aPythonDump << ", ";
907       aPythonDump << it->second;
908     }
909     aList->length( i );
910   }
911   catch(SALOME_Exception & S_ex) {
912     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
913   }
914
915   // Update Python script
916   if ( !_mapGroups.empty() ) // (IMP13463) avoid "SyntaxError: can't assign to []"
917     aPythonDump << " ] = " << _this() << ".GetGroups()";
918
919   return aList._retn();
920 }
921 //=============================================================================
922 /*!
923  *  Get number of groups existing in the mesh
924  */
925 //=============================================================================
926
927 CORBA::Long SMESH_Mesh_i::NbGroups() throw (SALOME::SALOME_Exception)
928 {
929   Unexpect aCatch(SALOME_SalomeException);
930   return _mapGroups.size();
931 }
932
933 //=============================================================================
934 /*! UnionGroups
935  *  New group is created. All mesh elements that are
936  *  present in initial groups are added to the new one
937  */
938 //=============================================================================
939 SMESH::SMESH_Group_ptr SMESH_Mesh_i::UnionGroups( SMESH::SMESH_GroupBase_ptr theGroup1,
940                                                   SMESH::SMESH_GroupBase_ptr theGroup2,
941                                                   const char* theName )
942   throw (SALOME::SALOME_Exception)
943 {
944   try
945   {
946     if ( theGroup1->_is_nil() || theGroup2->_is_nil() ||
947          theGroup1->GetType() != theGroup2->GetType() )
948       return SMESH::SMESH_Group::_nil();
949
950     // Create Union
951     SMESH::SMESH_Group_var aResGrp = CreateGroup( theGroup1->GetType(), theName );
952     if ( aResGrp->_is_nil() )
953       return SMESH::SMESH_Group::_nil();
954
955     SMESH::long_array_var anIds1 = theGroup1->GetListOfID();
956     SMESH::long_array_var anIds2 = theGroup2->GetListOfID();
957
958     TColStd_MapOfInteger aResMap;
959
960     for ( int i1 = 0, n1 = anIds1->length(); i1 < n1; i1++ )
961       aResMap.Add( anIds1[ i1 ] );
962
963     for ( int i2 = 0, n2 = anIds2->length(); i2 < n2; i2++ )
964       aResMap.Add( anIds2[ i2 ] );
965
966     SMESH::long_array_var aResIds = new SMESH::long_array;
967     aResIds->length( aResMap.Extent() );
968
969     int resI = 0;
970     TColStd_MapIteratorOfMapOfInteger anIter( aResMap );
971     for( ; anIter.More(); anIter.Next() )
972       aResIds[ resI++ ] = anIter.Key();
973
974     aResGrp->Add( aResIds );
975
976     // Clear python lines, created by CreateGroup() and Add()
977     SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy();
978     _gen_i->RemoveLastFromPythonScript(aStudy->StudyId());
979     _gen_i->RemoveLastFromPythonScript(aStudy->StudyId());
980
981     // Update Python script
982     TPythonDump() << aResGrp << " = " << _this() << ".UnionGroups( "
983                   << theGroup1 << ", " << theGroup2 << ", '"
984                   << theName << "' )";
985
986     return aResGrp._retn();
987   }
988   catch( ... )
989   {
990     return SMESH::SMESH_Group::_nil();
991   }
992 }
993
994 //=============================================================================
995 /*!
996   \brief Union list of groups. New group is created. All mesh elements that are
997    present in initial groups are added to the new one.
998   \param theGroups list of groups
999   \param theName name of group to be created
1000   \return pointer on the group
1001 */
1002 //=============================================================================
1003 SMESH::SMESH_Group_ptr SMESH_Mesh_i::UnionListOfGroups(const SMESH::ListOfGroups& theGroups,
1004                                                        const char*                theName )
1005 throw (SALOME::SALOME_Exception)
1006 {
1007   if ( !theName )
1008     return SMESH::SMESH_Group::_nil();
1009
1010   try
1011   {
1012     NCollection_Map< int > anIds;
1013     SMESH::ElementType aType = SMESH::ALL;
1014     for ( int g = 0, n = theGroups.length(); g < n; g++ )
1015     {
1016       SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ];
1017       if ( CORBA::is_nil( aGrp ) )
1018         continue;
1019
1020       // check type
1021       SMESH::ElementType aCurrType = aGrp->GetType();
1022       if ( aType == SMESH::ALL )
1023         aType = aCurrType;
1024       else 
1025       {
1026         if ( aType != aCurrType )
1027           return SMESH::SMESH_Group::_nil();
1028       }
1029
1030       // unite ids
1031       SMESH::long_array_var aCurrIds = aGrp->GetListOfID();
1032       for ( int i = 0, n = aCurrIds->length(); i < n; i++ )
1033       {
1034         int aCurrId = aCurrIds[ i ];
1035         anIds.Add( aCurrId );
1036       }
1037     }
1038
1039     // Create group
1040     SMESH::SMESH_Group_var aResGrp = CreateGroup( aType, theName );
1041     if ( aResGrp->_is_nil() )
1042       return SMESH::SMESH_Group::_nil();
1043     
1044     // Create array of identifiers
1045     SMESH::long_array_var aResIds = new SMESH::long_array;
1046     aResIds->length( anIds.Extent() );
1047     
1048     NCollection_Map< int >::Iterator anIter( anIds );
1049     for ( int i = 0; anIter.More(); anIter.Next(), i++ )
1050     {
1051       aResIds[ i ] = anIter.Value();
1052     }
1053     aResGrp->Add( aResIds );
1054
1055     // Clear python lines, created by CreateGroup() and Add()
1056     SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy();
1057     _gen_i->RemoveLastFromPythonScript( aStudy->StudyId() );
1058     _gen_i->RemoveLastFromPythonScript( aStudy->StudyId() );
1059
1060     // Update Python script
1061     
1062     TPythonDump() << aResGrp << " = " << _this() << ".UnionListOfGroups( "
1063                   << &theGroups << ", '" << theName << "' )";
1064
1065     return aResGrp._retn();
1066   }
1067   catch( ... )
1068   {
1069     return SMESH::SMESH_Group::_nil();
1070   }
1071 }
1072
1073 //=============================================================================
1074 /*! IntersectGroups
1075  *  New group is created. All mesh elements that are
1076  *  present in both initial groups are added to the new one.
1077  */
1078 //=============================================================================
1079 SMESH::SMESH_Group_ptr SMESH_Mesh_i::IntersectGroups( SMESH::SMESH_GroupBase_ptr theGroup1,
1080                                                       SMESH::SMESH_GroupBase_ptr theGroup2,
1081                                                       const char* theName )
1082   throw (SALOME::SALOME_Exception)
1083 {
1084   if ( theGroup1->_is_nil() || theGroup2->_is_nil() ||
1085        theGroup1->GetType() != theGroup2->GetType() )
1086     return SMESH::SMESH_Group::_nil();
1087
1088   // Create Intersection
1089   SMESH::SMESH_Group_var aResGrp = CreateGroup( theGroup1->GetType(), theName );
1090   if ( aResGrp->_is_nil() )
1091     return aResGrp;
1092
1093   SMESH::long_array_var anIds1 = theGroup1->GetListOfID();
1094   SMESH::long_array_var anIds2 = theGroup2->GetListOfID();
1095
1096   TColStd_MapOfInteger aMap1;
1097
1098   for ( int i1 = 0, n1 = anIds1->length(); i1 < n1; i1++ )
1099     aMap1.Add( anIds1[ i1 ] );
1100
1101   TColStd_SequenceOfInteger aSeq;
1102
1103   for ( int i2 = 0, n2 = anIds2->length(); i2 < n2; i2++ )
1104     if ( aMap1.Contains( anIds2[ i2 ] ) )
1105       aSeq.Append( anIds2[ i2 ] );
1106
1107   SMESH::long_array_var aResIds = new SMESH::long_array;
1108   aResIds->length( aSeq.Length() );
1109
1110   for ( int resI = 0, resN = aSeq.Length(); resI < resN; resI++ )
1111     aResIds[ resI ] = aSeq( resI + 1 );
1112
1113   aResGrp->Add( aResIds );
1114
1115   // Clear python lines, created by CreateGroup() and Add()
1116   SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy();
1117   _gen_i->RemoveLastFromPythonScript(aStudy->StudyId());
1118   _gen_i->RemoveLastFromPythonScript(aStudy->StudyId());
1119
1120   // Update Python script
1121   TPythonDump() << aResGrp << " = " << _this() << ".IntersectGroups( "
1122                 << theGroup1 << ", " << theGroup2 << ", '" << theName << "')";
1123
1124   return aResGrp._retn();
1125 }
1126
1127 //=============================================================================
1128 /*!
1129   \brief Intersect list of groups. New group is created. All mesh elements that 
1130   are present in all initial groups simultaneously are added to the new one.
1131   \param theGroups list of groups
1132   \param theName name of group to be created
1133   \return pointer on the group
1134 */
1135 //=============================================================================
1136 SMESH::SMESH_Group_ptr SMESH_Mesh_i::IntersectListOfGroups( 
1137   const SMESH::ListOfGroups& theGroups, const char* theName )
1138 throw (SALOME::SALOME_Exception)
1139 {
1140   if ( !theName )
1141     return SMESH::SMESH_Group::_nil();
1142
1143   try
1144   {
1145     NCollection_DataMap< int, int > anIdToCount;
1146     SMESH::ElementType aType = SMESH::ALL;
1147     for ( int g = 0, n = theGroups.length(); g < n; g++ )
1148     {
1149       SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ];
1150       if ( CORBA::is_nil( aGrp ) )
1151         continue;
1152
1153       // check type
1154       SMESH::ElementType aCurrType = aGrp->GetType();
1155       if ( aType == SMESH::ALL )
1156         aType = aCurrType;
1157       else 
1158       {
1159         if ( aType != aCurrType )
1160           return SMESH::SMESH_Group::_nil();
1161       }
1162
1163       // calculates number of occurance ids in groups
1164       SMESH::long_array_var aCurrIds = aGrp->GetListOfID();
1165       for ( int i = 0, n = aCurrIds->length(); i < n; i++ )
1166       {
1167         int aCurrId = aCurrIds[ i ];
1168         if ( !anIdToCount.IsBound( aCurrId ) )
1169           anIdToCount.Bind( aCurrId, 1 );
1170         else 
1171           anIdToCount( aCurrId ) = anIdToCount( aCurrId ) + 1;
1172       }
1173     }
1174     
1175     // create map of ids
1176     int nbGrp = theGroups.length();
1177     NCollection_Map< int > anIds;
1178     NCollection_DataMap< int, int >::Iterator anIter( anIdToCount );
1179     for ( ; anIter.More(); anIter.Next() )
1180     {
1181       int aCurrId = anIter.Key();
1182       int aCurrNb = anIter.Value();
1183       if ( aCurrNb == nbGrp )
1184         anIds.Add( aCurrId );
1185     }
1186
1187     // Create group
1188     SMESH::SMESH_Group_var aResGrp = CreateGroup( aType, theName );
1189     if ( aResGrp->_is_nil() )
1190       return SMESH::SMESH_Group::_nil();
1191     
1192     // Create array of identifiers
1193     SMESH::long_array_var aResIds = new SMESH::long_array;
1194     aResIds->length( anIds.Extent() );
1195     
1196     NCollection_Map< int >::Iterator aListIter( anIds );
1197     for ( int i = 0; aListIter.More(); aListIter.Next(), i++ )
1198     {
1199       aResIds[ i ] = aListIter.Value();
1200     }
1201     aResGrp->Add( aResIds );
1202
1203     // Clear python lines, created by CreateGroup() and Add()
1204     SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy();
1205     _gen_i->RemoveLastFromPythonScript( aStudy->StudyId() );
1206     _gen_i->RemoveLastFromPythonScript( aStudy->StudyId() );
1207
1208     // Update Python script
1209     
1210     TPythonDump() << aResGrp << " = " << _this() << ".IntersectListOfGroups( "
1211                   << &theGroups << ", '" << theName << "' )";
1212
1213     return aResGrp._retn();
1214   }
1215   catch( ... )
1216   {
1217     return SMESH::SMESH_Group::_nil();
1218   }
1219 }
1220
1221 //=============================================================================
1222 /*! CutGroups
1223  *  New group is created. All mesh elements that are present in
1224  *  main group but do not present in tool group are added to the new one
1225  */
1226 //=============================================================================
1227 SMESH::SMESH_Group_ptr SMESH_Mesh_i::CutGroups( SMESH::SMESH_GroupBase_ptr theGroup1,
1228                                                 SMESH::SMESH_GroupBase_ptr theGroup2,
1229                                                 const char* theName )
1230   throw (SALOME::SALOME_Exception)
1231 {
1232   if ( theGroup1->_is_nil() || theGroup2->_is_nil() ||
1233        theGroup1->GetType() != theGroup2->GetType() )
1234     return SMESH::SMESH_Group::_nil();
1235
1236   // Perform Cutting
1237   SMESH::SMESH_Group_var aResGrp = CreateGroup( theGroup1->GetType(), theName );
1238   if ( aResGrp->_is_nil() )
1239     return aResGrp;
1240
1241   SMESH::long_array_var anIds1 = theGroup1->GetListOfID();
1242   SMESH::long_array_var anIds2 = theGroup2->GetListOfID();
1243
1244   TColStd_MapOfInteger aMap2;
1245
1246   for ( int i2 = 0, n2 = anIds2->length(); i2 < n2; i2++ )
1247     aMap2.Add( anIds2[ i2 ] );
1248
1249   TColStd_SequenceOfInteger aSeq;
1250   for ( int i1 = 0, n1 = anIds1->length(); i1 < n1; i1++ )
1251     if ( !aMap2.Contains( anIds1[ i1 ] ) )
1252       aSeq.Append( anIds1[ i1 ] );
1253
1254   SMESH::long_array_var aResIds = new SMESH::long_array;
1255   aResIds->length( aSeq.Length() );
1256
1257   for ( int resI = 0, resN = aSeq.Length(); resI < resN; resI++ )
1258     aResIds[ resI ] = aSeq( resI + 1 );
1259
1260   aResGrp->Add( aResIds );
1261
1262   // Clear python lines, created by CreateGroup() and Add()
1263   SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy();
1264   _gen_i->RemoveLastFromPythonScript(aStudy->StudyId());
1265   _gen_i->RemoveLastFromPythonScript(aStudy->StudyId());
1266
1267   // Update Python script
1268   TPythonDump() << aResGrp << " = " << _this() << ".CutGroups( "
1269                 << theGroup1 << ", " << theGroup2 << ", '"
1270                 << theName << "' )";
1271
1272   return aResGrp._retn();
1273 }
1274
1275 //=============================================================================
1276 /*!
1277   \brief Cut lists of groups. New group is created. All mesh elements that are 
1278   present in main groups but do not present in tool groups are added to the new one
1279   \param theMainGroups list of main groups
1280   \param theToolGroups list of tool groups
1281   \param theName name of group to be created
1282   \return pointer on the group
1283 */
1284 //=============================================================================
1285 SMESH::SMESH_Group_ptr SMESH_Mesh_i::CutListOfGroups( 
1286   const SMESH::ListOfGroups& theMainGroups, 
1287   const SMESH::ListOfGroups& theToolGroups, 
1288   const char* theName )
1289   throw (SALOME::SALOME_Exception)
1290 {
1291   if ( !theName )
1292     return SMESH::SMESH_Group::_nil();
1293
1294   try
1295   {
1296     NCollection_Map< int > aToolIds;
1297     SMESH::ElementType aType = SMESH::ALL;
1298     int g, n;
1299     // iterate through tool groups
1300     for ( g = 0, n = theToolGroups.length(); g < n; g++ )
1301     {
1302       SMESH::SMESH_GroupBase_var aGrp = theToolGroups[ g ];
1303       if ( CORBA::is_nil( aGrp ) )
1304         continue;
1305
1306       // check type
1307       SMESH::ElementType aCurrType = aGrp->GetType();
1308       if ( aType == SMESH::ALL )
1309         aType = aCurrType;
1310       else 
1311       {
1312         if ( aType != aCurrType )
1313           return SMESH::SMESH_Group::_nil();
1314       }
1315
1316       // unite tool ids
1317       SMESH::long_array_var aCurrIds = aGrp->GetListOfID();
1318       for ( int i = 0, n = aCurrIds->length(); i < n; i++ )
1319       {
1320         int aCurrId = aCurrIds[ i ];
1321         aToolIds.Add( aCurrId );
1322       }
1323     }
1324
1325     NCollection_Map< int > anIds; // result
1326
1327     // Iterate through main group 
1328     for ( g = 0, n = theMainGroups.length(); g < n; g++ )
1329     {
1330       SMESH::SMESH_GroupBase_var aGrp = theMainGroups[ g ];
1331       if ( CORBA::is_nil( aGrp ) )
1332         continue;
1333
1334       // check type
1335       SMESH::ElementType aCurrType = aGrp->GetType();
1336       if ( aType == SMESH::ALL )
1337         aType = aCurrType;
1338       else 
1339       {
1340         if ( aType != aCurrType )
1341           return SMESH::SMESH_Group::_nil();
1342       }
1343
1344       // unite tool ids
1345       SMESH::long_array_var aCurrIds = aGrp->GetListOfID();
1346       for ( int i = 0, n = aCurrIds->length(); i < n; i++ )
1347       {
1348         int aCurrId = aCurrIds[ i ];
1349         if ( !aToolIds.Contains( aCurrId ) )
1350           anIds.Add( aCurrId );
1351       }
1352     }
1353
1354     // Create group
1355     SMESH::SMESH_Group_var aResGrp = CreateGroup( aType, theName );
1356     if ( aResGrp->_is_nil() )
1357       return SMESH::SMESH_Group::_nil();
1358     
1359     // Create array of identifiers
1360     SMESH::long_array_var aResIds = new SMESH::long_array;
1361     aResIds->length( anIds.Extent() );
1362     
1363     NCollection_Map< int >::Iterator anIter( anIds );
1364     for ( int i = 0; anIter.More(); anIter.Next(), i++ )
1365     {
1366       aResIds[ i ] = anIter.Value();
1367     }
1368     aResGrp->Add( aResIds );
1369
1370     // Clear python lines, created by CreateGroup() and Add()
1371     SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy();
1372     _gen_i->RemoveLastFromPythonScript( aStudy->StudyId() );
1373     _gen_i->RemoveLastFromPythonScript( aStudy->StudyId() );
1374
1375     // Update Python script
1376
1377     TPythonDump() << aResGrp << " = " << _this() << ".CutListOfGroups( "
1378                   << &theMainGroups << ", " << &theToolGroups << ", '"
1379                   << theName << "' )";
1380     
1381     return aResGrp._retn();
1382   }
1383   catch( ... )
1384   {
1385     return SMESH::SMESH_Group::_nil();
1386   }
1387 }
1388
1389 //=============================================================================
1390 /*!
1391   \brief Create groups of entities from existing groups of superior dimensions 
1392   System 
1393   1) extract all nodes from each group,
1394   2) combine all elements of specified dimension laying on these nodes.
1395   \param theGroups list of source groups 
1396   \param theElemType dimension of elements 
1397   \param theName name of new group
1398   \return pointer on new group
1399 */
1400 //=============================================================================
1401 SMESH::SMESH_Group_ptr SMESH_Mesh_i::CreateDimGroup( 
1402   const SMESH::ListOfGroups& theGroups, 
1403   SMESH::ElementType         theElemType, 
1404   const char*                theName )
1405   throw (SALOME::SALOME_Exception)
1406 {
1407   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
1408
1409   if ( !theName || !aMeshDS )
1410     return SMESH::SMESH_Group::_nil();
1411
1412   SMDSAbs_ElementType anElemType = (SMDSAbs_ElementType)theElemType;
1413
1414   try
1415   {
1416     // Create map of nodes from all groups 
1417
1418     NCollection_Map< int > aNodeMap;
1419     
1420     for ( int g = 0, n = theGroups.length(); g < n; g++ )
1421     {
1422       SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ];
1423       if ( CORBA::is_nil( aGrp ) )
1424         continue;
1425
1426       SMESH::ElementType aType = aGrp->GetType();
1427       if ( aType == SMESH::ALL )
1428         continue;
1429       else if ( aType == SMESH::NODE )
1430       {
1431         SMESH::long_array_var aCurrIds = aGrp->GetListOfID();
1432         for ( int i = 0, n = aCurrIds->length(); i < n; i++ )
1433         {
1434           int aCurrId = aCurrIds[ i ];
1435           const SMDS_MeshNode* aNode = aMeshDS->FindNode( aCurrId );
1436           if ( aNode )
1437             aNodeMap.Add( aNode->GetID() );
1438         }
1439       }
1440       else 
1441       {
1442         SMESH::long_array_var aCurrIds = aGrp->GetListOfID();
1443         for ( int i = 0, n = aCurrIds->length(); i < n; i++ )
1444         {
1445           int aCurrId = aCurrIds[ i ];
1446           const SMDS_MeshElement* anElem = aMeshDS->FindElement( aCurrId );
1447           if ( !anElem )
1448             continue;
1449           SMDS_ElemIteratorPtr aNodeIter = anElem->nodesIterator();
1450           while( aNodeIter->more() )
1451           {
1452             const SMDS_MeshNode* aNode = 
1453               dynamic_cast<const SMDS_MeshNode*>( aNodeIter->next() );
1454             if ( aNode )
1455               aNodeMap.Add( aNode->GetID() );
1456           }
1457         }
1458       }
1459     }
1460
1461     // Get result identifiers 
1462
1463     NCollection_Map< int > aResultIds;
1464     if ( theElemType == SMESH::NODE )
1465     {
1466       NCollection_Map< int >::Iterator aNodeIter( aNodeMap );
1467       for ( ; aNodeIter.More(); aNodeIter.Next() )
1468         aResultIds.Add( aNodeIter.Value() );
1469     }
1470     else
1471     {
1472       // Create list of elements of given dimension constructed on the nodes
1473       NCollection_Map< int > anElemList;
1474       NCollection_Map< int >::Iterator aNodeIter( aNodeMap );
1475       for ( ; aNodeIter.More(); aNodeIter.Next() )
1476       {
1477         const SMDS_MeshElement* aNode = 
1478           dynamic_cast<const SMDS_MeshElement*>( aMeshDS->FindNode( aNodeIter.Value() ) );
1479         if ( !aNode )
1480           continue;
1481
1482          SMDS_ElemIteratorPtr anElemIter = aNode->elementsIterator( anElemType );
1483         while( anElemIter->more() )
1484         {
1485           const SMDS_MeshElement* anElem = 
1486             dynamic_cast<const SMDS_MeshElement*>( anElemIter->next() );
1487           if ( anElem && anElem->GetType() == anElemType )
1488             anElemList.Add( anElem->GetID() );
1489         }
1490       }
1491
1492       // check whether all nodes of elements are present in nodes map
1493       NCollection_Map< int >::Iterator anIter( anElemList );
1494       for ( ; anIter.More(); anIter.Next() )
1495       {
1496         const SMDS_MeshElement* anElem = aMeshDS->FindElement( anIter.Value() );
1497         if ( !anElem )
1498           continue;
1499
1500         bool isOk = true;
1501         SMDS_ElemIteratorPtr aNodeIter = anElem->nodesIterator();
1502         while( aNodeIter->more() )
1503         {
1504           const SMDS_MeshNode* aNode = 
1505             dynamic_cast<const SMDS_MeshNode*>( aNodeIter->next() );
1506           if ( !aNode || !aNodeMap.Contains( aNode->GetID() ) )
1507           {
1508             isOk = false;
1509             break;
1510           }
1511         } 
1512         if ( isOk )
1513           aResultIds.Add( anElem->GetID() );
1514       }
1515     }
1516
1517     // Create group
1518
1519     SMESH::SMESH_Group_var aResGrp = CreateGroup( theElemType, theName );
1520     if ( aResGrp->_is_nil() )
1521       return SMESH::SMESH_Group::_nil();
1522     
1523     // Create array of identifiers
1524     SMESH::long_array_var aResIds = new SMESH::long_array;
1525     aResIds->length( aResultIds.Extent() );
1526     
1527     NCollection_Map< int >::Iterator aResIter( aResultIds );
1528     for ( int i = 0; aResIter.More(); aResIter.Next(), i++ )
1529       aResIds[ i ] = aResIter.Value();
1530     aResGrp->Add( aResIds );
1531
1532     // Remove strings corresponding to group creation
1533     SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy();
1534     _gen_i->RemoveLastFromPythonScript( aStudy->StudyId() );
1535     _gen_i->RemoveLastFromPythonScript( aStudy->StudyId() );
1536
1537     // Update Python script
1538     
1539     TPythonDump() << aResGrp << " = " << _this() << ".CreateDimGroup( "
1540                   << &theGroups << ", " << theElemType << ", '" << theName << "' )";
1541
1542     return aResGrp._retn();
1543   }
1544   catch( ... )
1545   {
1546     return SMESH::SMESH_Group::_nil();
1547   }
1548 }
1549
1550 //================================================================================
1551 /*!
1552  * \brief Remember GEOM group data
1553  */
1554 //================================================================================
1555
1556 void SMESH_Mesh_i::addGeomGroupData(GEOM::GEOM_Object_ptr theGeomObj,
1557                                     CORBA::Object_ptr     theSmeshObj)
1558 {
1559   if ( CORBA::is_nil( theGeomObj ) || theGeomObj->GetType() != GEOM_GROUP )
1560     return;
1561   // group SO
1562   SALOMEDS::Study_var   study  = _gen_i->GetCurrentStudy();
1563   SALOMEDS::SObject_var groupSO = _gen_i->ObjectToSObject( study, theGeomObj );
1564   if ( groupSO->_is_nil() )
1565     return;
1566   // group indices
1567   GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine();
1568   GEOM::GEOM_IGroupOperations_var groupOp =
1569     geomGen->GetIGroupOperations( _gen_i->GetCurrentStudyID() );
1570   GEOM::ListOfLong_var ids = groupOp->GetObjects( theGeomObj );
1571
1572   // store data
1573   _geomGroupData.push_back( TGeomGroupData() );
1574   TGeomGroupData & groupData = _geomGroupData.back();
1575   // entry
1576   CORBA::String_var entry = groupSO->GetID();
1577   groupData._groupEntry = entry.in();
1578   // indices
1579   for ( int i = 0; i < ids->length(); ++i )
1580     groupData._indices.insert( ids[i] );
1581   // SMESH object
1582   groupData._smeshObject = theSmeshObj;
1583 }
1584
1585 //================================================================================
1586 /*!
1587  * Remove GEOM group data relating to removed smesh object
1588  */
1589 //================================================================================
1590
1591 void SMESH_Mesh_i::removeGeomGroupData(CORBA::Object_ptr theSmeshObj)
1592 {
1593   list<TGeomGroupData>::iterator
1594     data = _geomGroupData.begin(), dataEnd = _geomGroupData.end();
1595   for ( ; data != dataEnd; ++data ) {
1596     if ( theSmeshObj->_is_equivalent( data->_smeshObject )) {
1597       _geomGroupData.erase( data );
1598       return;
1599     }
1600   }
1601 }
1602
1603 //================================================================================
1604 /*!
1605  * \brief Return new group contents if it has been changed and update group data
1606  */
1607 //================================================================================
1608
1609 TopoDS_Shape SMESH_Mesh_i::newGroupShape( TGeomGroupData & groupData)
1610 {
1611   TopoDS_Shape newShape;
1612
1613   // get geom group
1614   SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
1615   if ( study->_is_nil() ) return newShape; // means "not changed"
1616   SALOMEDS::SObject_var groupSO = study->FindObjectID( groupData._groupEntry.c_str() );
1617   if ( !groupSO->_is_nil() )
1618   {
1619     CORBA::Object_var groupObj = _gen_i->SObjectToObject( groupSO );
1620     if ( CORBA::is_nil( groupObj )) return newShape;
1621     GEOM::GEOM_Object_var geomGroup = GEOM::GEOM_Object::_narrow( groupObj );
1622
1623     // get indices of group items
1624     set<int> curIndices;
1625     GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine();
1626     GEOM::GEOM_IGroupOperations_var groupOp =
1627       geomGen->GetIGroupOperations( _gen_i->GetCurrentStudyID() );
1628     GEOM::ListOfLong_var ids = groupOp->GetObjects( geomGroup );
1629     for ( int i = 0; i < ids->length(); ++i )
1630       curIndices.insert( ids[i] );
1631
1632     if ( groupData._indices == curIndices )
1633       return newShape; // group not changed
1634
1635     // update data
1636     groupData._indices = curIndices;
1637
1638     GEOM_Client* geomClient = _gen_i->GetShapeReader();
1639     if ( !geomClient ) return newShape;
1640     TCollection_AsciiString groupIOR = geomGen->GetStringFromIOR( geomGroup );
1641     geomClient->RemoveShapeFromBuffer( groupIOR );
1642     newShape = _gen_i->GeomObjectToShape( geomGroup );
1643   }    
1644
1645   if ( newShape.IsNull() ) {
1646     // geom group becomes empty - return empty compound
1647     TopoDS_Compound compound;
1648     BRep_Builder().MakeCompound(compound);
1649     newShape = compound;
1650   }
1651   return newShape;
1652 }
1653
1654 namespace {
1655   //=============================================================================
1656   /*!
1657    * \brief Storage of shape and index used in CheckGeomGroupModif()
1658    */
1659   //=============================================================================
1660   struct TIndexedShape {
1661     int          _index;
1662     TopoDS_Shape _shape;
1663     TIndexedShape( int i, const TopoDS_Shape& s ):_index(i), _shape(s) {}
1664   };
1665 }
1666 //=============================================================================
1667 /*!
1668  * \brief Update objects depending on changed geom groups
1669  * 
1670  * NPAL16168: geometrical group edition from a submesh don't modifiy mesh computation
1671  * issue 0020210: Update of a smesh group after modification of the associated geom group
1672  */
1673 //=============================================================================
1674
1675 void SMESH_Mesh_i::CheckGeomGroupModif()
1676 {
1677   if ( !_impl->HasShapeToMesh() ) return;
1678
1679   SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
1680   if ( study->_is_nil() ) return;
1681
1682   CORBA::Long nbEntities = NbNodes() + NbElements();
1683
1684   // Check if group contents changed
1685
1686   typedef map< string, TopoDS_Shape > TEntry2Geom;
1687   TEntry2Geom newGroupContents;
1688
1689   list<TGeomGroupData>::iterator
1690     data = _geomGroupData.begin(), dataEnd = _geomGroupData.end();
1691   for ( ; data != dataEnd; ++data )
1692   {
1693     pair< TEntry2Geom::iterator, bool > it_new =
1694       newGroupContents.insert( make_pair( data->_groupEntry, TopoDS_Shape() ));
1695     bool processedGroup    = !it_new.second;
1696     TopoDS_Shape& newShape = it_new.first->second;
1697     if ( !processedGroup )
1698       newShape = newGroupShape( *data );
1699     if ( newShape.IsNull() )
1700       continue; // no changes
1701
1702     if ( processedGroup ) { // update group indices
1703       list<TGeomGroupData>::iterator data2 = data;
1704       for ( --data2; data2->_groupEntry != data->_groupEntry; --data2) {}
1705       data->_indices = data2->_indices;
1706     }
1707
1708     // Update SMESH objects according to new GEOM group contents
1709
1710     SMESH::SMESH_subMesh_var submesh = SMESH::SMESH_subMesh::_narrow( data->_smeshObject );
1711     if ( !submesh->_is_nil() ) // -------------- Sub mesh ---------------------
1712     {
1713       int oldID = submesh->GetId();
1714       if ( _mapSubMeshIor.find( oldID ) == _mapSubMeshIor.end() )
1715         continue;
1716       TopoDS_Shape oldShape = _mapSubMesh[oldID]->GetSubShape();
1717
1718       // update hypotheses
1719       list <const SMESHDS_Hypothesis * > hyps = _impl->GetHypothesisList(oldShape);
1720       list <const SMESHDS_Hypothesis * >::iterator hypIt;
1721       for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
1722       {
1723         _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
1724         _impl->AddHypothesis   ( newShape, (*hypIt)->GetID());
1725       }
1726       // care of submeshes
1727       SMESH_subMesh* newSubmesh = _impl->GetSubMesh( newShape );
1728       int newID = newSubmesh->GetId();
1729       if ( newID != oldID ) {
1730         _mapSubMesh   [ newID ] = newSubmesh;
1731         _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
1732         _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
1733         _mapSubMesh.   erase(oldID);
1734         _mapSubMesh_i. erase(oldID);
1735         _mapSubMeshIor.erase(oldID);
1736         _mapSubMesh_i [ newID ]->changeLocalId( newID );
1737       }
1738       continue;
1739     }
1740
1741     SMESH::SMESH_GroupOnGeom_var smeshGroup =
1742       SMESH::SMESH_GroupOnGeom::_narrow( data->_smeshObject );
1743     if ( !smeshGroup->_is_nil() ) // ------------ GROUP -----------------------
1744     {
1745       SMESH_GroupOnGeom_i* group_i = SMESH::DownCast<SMESH_GroupOnGeom_i*>( smeshGroup );
1746       if ( group_i ) {
1747         ::SMESH_Group* group = _impl->GetGroup( group_i->GetLocalID() );
1748         SMESHDS_GroupOnGeom* ds = static_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() );
1749         ds->SetShape( newShape );
1750       }
1751       continue;
1752     }
1753
1754     SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( data->_smeshObject );
1755     if ( !mesh->_is_nil() ) // -------------- MESH ----------------------------
1756     {
1757       // Remove groups and submeshes basing on removed sub-shapes
1758
1759       TopTools_MapOfShape newShapeMap;
1760       TopoDS_Iterator shapeIt( newShape );
1761       for ( ; shapeIt.More(); shapeIt.Next() )
1762         newShapeMap.Add( shapeIt.Value() );
1763
1764       SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
1765       for ( shapeIt.Initialize( meshDS->ShapeToMesh() ); shapeIt.More(); shapeIt.Next() )
1766       {
1767         if ( newShapeMap.Contains( shapeIt.Value() ))
1768           continue;
1769         TopTools_IndexedMapOfShape oldShapeMap;
1770         TopExp::MapShapes( shapeIt.Value(), oldShapeMap );
1771         for ( int i = 1; i <= oldShapeMap.Extent(); ++i )
1772         {
1773           const TopoDS_Shape& oldShape = oldShapeMap(i);
1774           int oldInd = meshDS->ShapeToIndex( oldShape );
1775           // -- submeshes --
1776           map<int, SMESH::SMESH_subMesh_ptr>::iterator i_smIor = _mapSubMeshIor.find( oldInd );
1777           if ( i_smIor != _mapSubMeshIor.end() ) {
1778             RemoveSubMesh( i_smIor->second ); // one submesh per shape index
1779           }
1780           // --- groups ---
1781           map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.begin();
1782           for ( ; i_grp != _mapGroups.end(); ++i_grp )
1783           {
1784             // check if a group bases on oldInd shape
1785             SMESHDS_GroupOnGeom* grpOnGeom = 0;
1786             if ( ::SMESH_Group* g = _impl->GetGroup( i_grp->first ))
1787               grpOnGeom = dynamic_cast<SMESHDS_GroupOnGeom*>( g->GetGroupDS() );
1788             if ( grpOnGeom && oldShape.IsSame( grpOnGeom->GetShape() ))
1789             { // remove
1790               RemoveGroup( i_grp->second ); // several groups can base on same shape
1791               i_grp = _mapGroups.begin(); // _mapGroups changed - restart iteration
1792             }
1793           }
1794         }
1795       }
1796       // Reassign hypotheses and update groups after setting the new shape to mesh
1797
1798       // collect anassigned hypotheses
1799       typedef list< pair< TIndexedShape, list<const SMESHDS_Hypothesis*> > > TShapeHypList;
1800       list <const SMESHDS_Hypothesis * >::const_iterator hypIt;
1801       TShapeHypList assignedHyps;
1802       for ( int i = 1; i <= meshDS->MaxShapeIndex(); ++i )
1803       {
1804         const TopoDS_Shape& oldShape = meshDS->IndexToShape(i);
1805         list<const SMESHDS_Hypothesis*> hyps = meshDS->GetHypothesis( oldShape );// copy
1806         if ( !hyps.empty() ) {
1807           assignedHyps.push_back( make_pair( TIndexedShape(i,oldShape), hyps ));
1808           for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
1809             _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
1810         }
1811       }
1812       // collect shapes supporting groups
1813       typedef list < pair< TIndexedShape, SMDSAbs_ElementType > > TShapeTypeList;
1814       TShapeTypeList groupData;
1815       const set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
1816       set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1817       for ( ; grIt != groups.end(); ++grIt )
1818       {
1819         if ( SMESHDS_GroupOnGeom* gog = dynamic_cast<SMESHDS_GroupOnGeom*>( *grIt ))
1820           groupData.push_back
1821             ( make_pair( TIndexedShape( gog->GetID(),gog->GetShape()), gog->GetType()));
1822       }
1823       // set new shape to mesh -> DS of submeshes and geom groups is deleted
1824       _impl->ShapeToMesh( newShape );
1825       
1826       // reassign hypotheses
1827       TShapeHypList::iterator indS_hyps = assignedHyps.begin();
1828       for ( ; indS_hyps != assignedHyps.end(); ++indS_hyps )
1829       {
1830         TIndexedShape&                   geom = indS_hyps->first;
1831         list<const SMESHDS_Hypothesis*>& hyps = indS_hyps->second;
1832         int oldID = geom._index;
1833         int newID = meshDS->ShapeToIndex( geom._shape );
1834         if ( !newID )
1835           continue;
1836         if ( oldID == 1 ) { // main shape
1837           newID = 1;
1838           geom._shape = newShape;
1839         }
1840         for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
1841           _impl->AddHypothesis( geom._shape, (*hypIt)->GetID());
1842         // care of submeshes
1843         SMESH_subMesh* newSubmesh = _impl->GetSubMesh( geom._shape );
1844         if ( newID != oldID ) {
1845           _mapSubMesh   [ newID ] = newSubmesh;
1846           _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
1847           _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
1848           _mapSubMesh.   erase(oldID);
1849           _mapSubMesh_i. erase(oldID);
1850           _mapSubMeshIor.erase(oldID);
1851           _mapSubMesh_i [ newID ]->changeLocalId( newID );
1852         }
1853       }
1854       // recreate groups
1855       TShapeTypeList::iterator geomType = groupData.begin();
1856       for ( ; geomType != groupData.end(); ++geomType )
1857       {
1858         const TIndexedShape& geom = geomType->first;
1859         int oldID = geom._index;
1860         if ( _mapGroups.find( oldID ) == _mapGroups.end() )
1861           continue;
1862         // get group name
1863         SALOMEDS::SObject_var groupSO = _gen_i->ObjectToSObject( study,_mapGroups[oldID] );
1864         CORBA::String_var     name    = groupSO->GetName();
1865         // update
1866         SMESH_GroupBase_i* group_i    = SMESH::DownCast<SMESH_GroupBase_i*>(_mapGroups[oldID] );
1867         int newID;
1868         if ( group_i && _impl->AddGroup( geomType->second, name.in(), newID, geom._shape ))
1869           group_i->changeLocalId( newID );
1870       }
1871
1872       break; // everything has been updated
1873
1874     } // update mesh
1875   } // loop on group data
1876
1877   // Update icons
1878
1879   CORBA::Long newNbEntities = NbNodes() + NbElements();
1880   list< SALOMEDS::SObject_var > soToUpdateIcons;
1881   if ( newNbEntities != nbEntities )
1882   {
1883     // Add all SObjects with icons
1884     soToUpdateIcons.push_back( _gen_i->ObjectToSObject( study, _this() )); // mesh
1885
1886     for (map<int, SMESH::SMESH_subMesh_ptr>::iterator i_sm = _mapSubMeshIor.begin();
1887          i_sm != _mapSubMeshIor.end(); ++i_sm ) // submeshes
1888       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( study, i_sm->second ));
1889
1890     for ( map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
1891           i_gr != _mapGroups.end(); ++i_gr ) // groups
1892       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( study, i_gr->second ));
1893   }
1894
1895   list< SALOMEDS::SObject_var >::iterator so = soToUpdateIcons.begin();
1896   for ( ; so != soToUpdateIcons.end(); ++so )
1897     _gen_i->SetPixMap( *so, "ICON_SMESH_TREE_MESH_WARN" );
1898 }
1899
1900 //=============================================================================
1901 /*!
1902  * \brief Create standalone group instead if group on geometry
1903  */
1904 //=============================================================================
1905
1906 SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupOnGeom_ptr theGroup )
1907 {
1908   SMESH::SMESH_Group_var aGroup;
1909   if ( theGroup->_is_nil() )
1910     return aGroup._retn();
1911
1912   Unexpect aCatch(SALOME_SalomeException);
1913
1914   SMESH_GroupBase_i* aGroupToRem =
1915     dynamic_cast<SMESH_GroupBase_i*>( SMESH_Gen_i::GetServant( theGroup ).in() );
1916   if ( !aGroupToRem )
1917     return aGroup._retn();
1918
1919   int anId = aGroupToRem->GetLocalID();
1920   if ( !_impl->ConvertToStandalone( anId ) )
1921     return aGroup._retn();
1922   removeGeomGroupData( theGroup );
1923
1924   SMESH_GroupBase_i* aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
1925
1926   // remove old instance of group from own map
1927   _mapGroups.erase( anId );
1928
1929   SALOMEDS::StudyBuilder_var builder;
1930   SALOMEDS::SObject_var aGroupSO;
1931   SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy();
1932   if ( !aStudy->_is_nil() )  {
1933     builder = aStudy->NewBuilder();
1934     aGroupSO = _gen_i->ObjectToSObject( aStudy, theGroup );
1935     if ( !aGroupSO->_is_nil() ) {
1936
1937     // remove reference to geometry
1938     SALOMEDS::ChildIterator_var chItr = aStudy->NewChildIterator(aGroupSO);
1939     for ( ; chItr->More(); chItr->Next() )
1940       // Remove group's child SObject
1941       builder->RemoveObject( chItr->Value() );
1942
1943       // Update Python script
1944       TPythonDump() << aGroupSO << " = " << _this() << ".ConvertToStandalone( "
1945                     << aGroupSO << " )";
1946     }
1947   }
1948
1949   // PAL7962: san -- To ensure correct mapping of servant and correct reference counting in GenericObj_i
1950   SMESH_Gen_i::GetPOA()->activate_object( aGroupImpl );
1951   aGroupImpl->Register();
1952   // PAL7962: san -- To ensure correct mapping of servant and correct reference counting in GenericObj_i
1953
1954   // remember new group in own map
1955   aGroup = SMESH::SMESH_Group::_narrow( aGroupImpl->_this() );
1956   _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
1957
1958   // register CORBA object for persistence
1959   /*int nextId =*/ _gen_i->RegisterObject( aGroup );
1960
1961   builder->SetIOR( aGroupSO, _gen_i->GetORB()->object_to_string( aGroup ) );
1962
1963   return aGroup._retn();
1964 }
1965
1966 //=============================================================================
1967 /*!
1968  *
1969  */
1970 //=============================================================================
1971
1972 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::createSubMesh( GEOM::GEOM_Object_ptr theSubShapeObject )
1973 {
1974   if(MYDEBUG) MESSAGE( "createSubMesh" );
1975   TopoDS_Shape myLocSubShape = _gen_i->GeomObjectToShape(theSubShapeObject);
1976
1977   ::SMESH_subMesh * mySubMesh = _impl->GetSubMesh(myLocSubShape);
1978   int subMeshId = _impl->GetMeshDS()->ShapeToIndex( myLocSubShape );
1979   SMESH_subMesh_i *subMeshServant = new SMESH_subMesh_i(myPOA, _gen_i, this, subMeshId);
1980   SMESH::SMESH_subMesh_var subMesh
1981     = SMESH::SMESH_subMesh::_narrow(subMeshServant->_this());
1982
1983   _mapSubMesh[subMeshId] = mySubMesh;
1984   _mapSubMesh_i[subMeshId] = subMeshServant;
1985   _mapSubMeshIor[subMeshId] = SMESH::SMESH_subMesh::_duplicate(subMesh);
1986
1987   // register CORBA object for persistence
1988   int nextId = _gen_i->RegisterObject( subMesh );
1989   if(MYDEBUG) MESSAGE( "Add submesh to map with id = "<< nextId);
1990
1991   // to track changes of GEOM groups
1992   addGeomGroupData( theSubShapeObject, subMesh );
1993
1994   return subMesh._retn();
1995 }
1996
1997 //=======================================================================
1998 //function : getSubMesh
1999 //purpose  :
2000 //=======================================================================
2001
2002 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::getSubMesh(int shapeID)
2003 {
2004   map<int, SMESH::SMESH_subMesh_ptr>::iterator it = _mapSubMeshIor.find( shapeID );
2005   if ( it == _mapSubMeshIor.end() )
2006     return SMESH::SMESH_subMesh::_nil();
2007
2008   return SMESH::SMESH_subMesh::_duplicate( (*it).second );
2009 }
2010
2011
2012 //=============================================================================
2013 /*!
2014  *
2015  */
2016 //=============================================================================
2017
2018 void SMESH_Mesh_i::removeSubMesh (SMESH::SMESH_subMesh_ptr theSubMesh,
2019                                   GEOM::GEOM_Object_ptr    theSubShapeObject )
2020 {
2021   MESSAGE("SMESH_Mesh_i::removeSubMesh()");
2022   if ( theSubMesh->_is_nil() /*|| theSubShapeObject->_is_nil()*/ )
2023     return;
2024
2025   if ( theSubShapeObject->_is_nil() )  // not published shape (IPAL13617)
2026   {
2027     CORBA::Long shapeId = theSubMesh->GetId();
2028     if ( _mapSubMesh.find( shapeId ) != _mapSubMesh.end())
2029     {
2030       TopoDS_Shape S = _mapSubMesh[ shapeId ]->GetSubShape();
2031       if ( !S.IsNull() )
2032       {
2033         list<const SMESHDS_Hypothesis*> hyps = _impl->GetHypothesisList( S );
2034         list<const SMESHDS_Hypothesis*>::const_iterator hyp = hyps.begin();
2035         for ( ; hyp != hyps.end(); ++hyp )
2036           _impl->RemoveHypothesis(S, (*hyp)->GetID());
2037       }
2038     }
2039   }
2040   else
2041   {
2042     try {
2043       SMESH::ListOfHypothesis_var aHypList = GetHypothesisList( theSubShapeObject );
2044       for ( int i = 0, n = aHypList->length(); i < n; i++ ) {
2045         removeHypothesis( theSubShapeObject, aHypList[i] );
2046       }
2047     }
2048     catch( const SALOME::SALOME_Exception& ) {
2049       INFOS("SMESH_Mesh_i::removeSubMesh(): exception caught!");
2050     }
2051     removeGeomGroupData( theSubShapeObject );
2052   }
2053   int subMeshId = theSubMesh->GetId();
2054
2055   _mapSubMesh.erase(subMeshId);
2056   _mapSubMesh_i.erase(subMeshId);
2057   _mapSubMeshIor.erase(subMeshId);
2058   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::removeSubMesh() completed");
2059 }
2060
2061 //=============================================================================
2062 /*!
2063  *
2064  */
2065 //=============================================================================
2066
2067 SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType theElemType,
2068                                                       const char*         theName,
2069                                                       const TopoDS_Shape& theShape )
2070 {
2071   int anId;
2072   SMESH::SMESH_GroupBase_var aGroup;
2073   if ( _impl->AddGroup( (SMDSAbs_ElementType)theElemType, theName, anId, theShape )) {
2074     SMESH_GroupBase_i* aGroupImpl;
2075     if ( !theShape.IsNull() )
2076       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
2077     else
2078       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
2079
2080     // PAL7962: san -- To ensure correct mapping of servant and correct reference counting in GenericObj_i
2081     SMESH_Gen_i::GetPOA()->activate_object( aGroupImpl );
2082     aGroupImpl->Register();
2083     // PAL7962: san -- To ensure correct mapping of servant and correct reference counting in GenericObj_i
2084
2085     aGroup = SMESH::SMESH_GroupBase::_narrow( aGroupImpl->_this() );
2086     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
2087
2088     // register CORBA object for persistence
2089     int nextId = _gen_i->RegisterObject( aGroup );
2090     if(MYDEBUG) MESSAGE( "Add group to map with id = "<< nextId);
2091
2092     // to track changes of GEOM groups
2093     if ( !theShape.IsNull() ) {
2094       GEOM::GEOM_Object_var geom = _gen_i->ShapeToGeomObject( theShape );
2095       addGeomGroupData( geom, aGroup );
2096     }
2097   }
2098   return aGroup._retn();
2099 }
2100
2101 //=============================================================================
2102 /*!
2103  * SMESH_Mesh_i::removeGroup
2104  *
2105  * Should be called by ~SMESH_Group_i()
2106  */
2107 //=============================================================================
2108
2109 void SMESH_Mesh_i::removeGroup( const int theId )
2110 {
2111   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::removeGroup()" );
2112   if ( _mapGroups.find( theId ) != _mapGroups.end() ) {
2113     removeGeomGroupData( _mapGroups[theId] );
2114     _mapGroups.erase( theId );
2115     _impl->RemoveGroup( theId );
2116   }
2117 }
2118
2119
2120 //=============================================================================
2121 /*!
2122  *
2123  */
2124 //=============================================================================
2125
2126 SMESH::log_array * SMESH_Mesh_i::GetLog(CORBA::Boolean clearAfterGet)
2127 throw(SALOME::SALOME_Exception)
2128 {
2129   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::GetLog");
2130
2131   SMESH::log_array_var aLog;
2132   try{
2133     list < SMESHDS_Command * >logDS = _impl->GetLog();
2134     aLog = new SMESH::log_array;
2135     int indexLog = 0;
2136     int lg = logDS.size();
2137     SCRUTE(lg);
2138     aLog->length(lg);
2139     list < SMESHDS_Command * >::iterator its = logDS.begin();
2140     while(its != logDS.end()){
2141       SMESHDS_Command *com = *its;
2142       int comType = com->GetType();
2143       //SCRUTE(comType);
2144       int lgcom = com->GetNumber();
2145       //SCRUTE(lgcom);
2146       const list < int >&intList = com->GetIndexes();
2147       int inum = intList.size();
2148       //SCRUTE(inum);
2149       list < int >::const_iterator ii = intList.begin();
2150       const list < double >&coordList = com->GetCoords();
2151       int rnum = coordList.size();
2152       //SCRUTE(rnum);
2153       list < double >::const_iterator ir = coordList.begin();
2154       aLog[indexLog].commandType = comType;
2155       aLog[indexLog].number = lgcom;
2156       aLog[indexLog].coords.length(rnum);
2157       aLog[indexLog].indexes.length(inum);
2158       for(int i = 0; i < rnum; i++){
2159         aLog[indexLog].coords[i] = *ir;
2160         //MESSAGE(" "<<i<<" "<<ir.Value());
2161         ir++;
2162       }
2163       for(int i = 0; i < inum; i++){
2164         aLog[indexLog].indexes[i] = *ii;
2165         //MESSAGE(" "<<i<<" "<<ii.Value());
2166         ii++;
2167       }
2168       indexLog++;
2169       its++;
2170     }
2171     if(clearAfterGet)
2172       _impl->ClearLog();
2173   }
2174   catch(SALOME_Exception & S_ex){
2175     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
2176   }
2177   return aLog._retn();
2178 }
2179
2180
2181 //=============================================================================
2182 /*!
2183  *
2184  */
2185 //=============================================================================
2186
2187 void SMESH_Mesh_i::ClearLog() throw(SALOME::SALOME_Exception)
2188 {
2189   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::ClearLog");
2190   _impl->ClearLog();
2191 }
2192
2193 //=============================================================================
2194 /*!
2195  *
2196  */
2197 //=============================================================================
2198
2199 CORBA::Long SMESH_Mesh_i::GetId()throw(SALOME::SALOME_Exception)
2200 {
2201   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::GetId");
2202   return _id;
2203 }
2204
2205 //=============================================================================
2206 /*!
2207  *
2208  */
2209 //=============================================================================
2210
2211 CORBA::Long SMESH_Mesh_i::GetStudyId()throw(SALOME::SALOME_Exception)
2212 {
2213   return _studyId;
2214 }
2215
2216 //=============================================================================
2217 /*!
2218  *
2219  */
2220 //=============================================================================
2221
2222 void SMESH_Mesh_i::SetImpl(::SMESH_Mesh * impl)
2223 {
2224   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::SetImpl");
2225   _impl = impl;
2226 }
2227
2228 //=============================================================================
2229 /*!
2230  *
2231  */
2232 //=============================================================================
2233
2234 ::SMESH_Mesh & SMESH_Mesh_i::GetImpl()
2235 {
2236   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::GetImpl()");
2237   return *_impl;
2238 }
2239
2240 //=============================================================================
2241 /*!
2242  * Return mesh editor
2243  */
2244 //=============================================================================
2245
2246 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditor()
2247 {
2248   // Create MeshEditor
2249   SMESH_MeshEditor_i *aMeshEditor = new SMESH_MeshEditor_i( this, false );
2250   SMESH::SMESH_MeshEditor_var aMesh = aMeshEditor->_this();
2251
2252   // Update Python script
2253   TPythonDump() << aMeshEditor << " = " << _this() << ".GetMeshEditor()";
2254
2255   return aMesh._retn();
2256 }
2257
2258 //=============================================================================
2259 /*!
2260  * Return mesh edition previewer
2261  */
2262 //=============================================================================
2263
2264 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditPreviewer()
2265 {
2266   SMESH_MeshEditor_i *aMeshEditor = new SMESH_MeshEditor_i( this, true );
2267   SMESH::SMESH_MeshEditor_var aMesh = aMeshEditor->_this();
2268   return aMesh._retn();
2269 }
2270
2271 //================================================================================
2272 /*!
2273  * \brief Return true if the mesh has been edited since a last total re-compute
2274  *        and those modifications may prevent successful partial re-compute
2275  */
2276 //================================================================================
2277
2278 CORBA::Boolean SMESH_Mesh_i::HasModificationsToDiscard() throw(SALOME::SALOME_Exception)
2279 {
2280   Unexpect aCatch(SALOME_SalomeException);
2281   return _impl->HasModificationsToDiscard();
2282 }
2283
2284 //=============================================================================
2285 /*!
2286  *
2287  */
2288 //=============================================================================
2289 void SMESH_Mesh_i::SetAutoColor(CORBA::Boolean theAutoColor) throw(SALOME::SALOME_Exception)
2290 {
2291   Unexpect aCatch(SALOME_SalomeException);
2292   _impl->SetAutoColor(theAutoColor);
2293 }
2294
2295 //=============================================================================
2296 /*!
2297  *
2298  */
2299 //=============================================================================
2300 CORBA::Boolean SMESH_Mesh_i::GetAutoColor() throw(SALOME::SALOME_Exception)
2301 {
2302   Unexpect aCatch(SALOME_SalomeException);
2303   return _impl->GetAutoColor();
2304 }
2305
2306
2307 //=============================================================================
2308 /*!
2309  *  Export in different formats
2310  */
2311 //=============================================================================
2312
2313 CORBA::Boolean SMESH_Mesh_i::HasDuplicatedGroupNamesMED()
2314 {
2315   return _impl->HasDuplicatedGroupNamesMED();
2316 }
2317
2318 void SMESH_Mesh_i::PrepareForWriting (const char* file, bool overwrite)
2319 {
2320   TCollection_AsciiString aFullName ((char*)file);
2321   OSD_Path aPath (aFullName);
2322   OSD_File aFile (aPath);
2323   if (aFile.Exists()) {
2324     // existing filesystem node
2325     if (aFile.KindOfFile() == OSD_FILE) {
2326       if (aFile.IsWriteable()) {
2327         if (overwrite) {
2328           aFile.Reset();
2329           aFile.Remove();
2330         }
2331         if (aFile.Failed()) {
2332           TCollection_AsciiString msg ("File ");
2333           msg += aFullName + " cannot be replaced.";
2334           THROW_SALOME_CORBA_EXCEPTION(msg.ToCString(), SALOME::BAD_PARAM);
2335         }
2336       } else {
2337         TCollection_AsciiString msg ("File ");
2338         msg += aFullName + " cannot be overwritten.";
2339         THROW_SALOME_CORBA_EXCEPTION(msg.ToCString(), SALOME::BAD_PARAM);
2340       }
2341     } else {
2342       TCollection_AsciiString msg ("Location ");
2343       msg += aFullName + " is not a file.";
2344       THROW_SALOME_CORBA_EXCEPTION(msg.ToCString(), SALOME::BAD_PARAM);
2345     }
2346   } else {
2347     // nonexisting file; check if it can be created
2348     aFile.Reset();
2349     aFile.Build(OSD_WriteOnly, OSD_Protection());
2350     if (aFile.Failed()) {
2351       TCollection_AsciiString msg ("You cannot create the file ");
2352       msg += aFullName + ". Check the directory existance and access rights.";
2353       THROW_SALOME_CORBA_EXCEPTION(msg.ToCString(), SALOME::BAD_PARAM);
2354     } else {
2355       aFile.Close();
2356       aFile.Remove();
2357     }
2358   }
2359 }
2360
2361 void SMESH_Mesh_i::ExportToMEDX (const char* file,
2362                                  CORBA::Boolean auto_groups,
2363                                  SMESH::MED_VERSION theVersion,
2364                                  CORBA::Boolean overwrite)
2365   throw(SALOME::SALOME_Exception)
2366 {
2367   Unexpect aCatch(SALOME_SalomeException);
2368
2369   // Perform Export
2370   PrepareForWriting(file, overwrite);
2371   const char* aMeshName = "Mesh";
2372   SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy();
2373   if ( !aStudy->_is_nil() ) {
2374     SALOMEDS::SObject_var aMeshSO = _gen_i->ObjectToSObject( aStudy, _this() );
2375     if ( !aMeshSO->_is_nil() ) {
2376       aMeshName = aMeshSO->GetName();
2377       // asv : 27.10.04 : fix of 6903: check for StudyLocked before adding attributes
2378       if ( !aStudy->GetProperties()->IsLocked() )
2379         {
2380         SALOMEDS::GenericAttribute_var anAttr;
2381         SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder();
2382         SALOMEDS::AttributeExternalFileDef_var aFileName;
2383         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeExternalFileDef");
2384         aFileName = SALOMEDS::AttributeExternalFileDef::_narrow(anAttr);
2385         ASSERT(!aFileName->_is_nil());
2386         aFileName->SetValue(file);
2387         SALOMEDS::AttributeFileType_var aFileType;
2388         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeFileType");
2389         aFileType = SALOMEDS::AttributeFileType::_narrow(anAttr);
2390         ASSERT(!aFileType->_is_nil());
2391         aFileType->SetValue("FICHIERMED");
2392         }
2393     }
2394   }
2395   // Update Python script
2396   // set name of mesh before export
2397   TPythonDump() << _gen_i << ".SetName(" << _this() << ", '" << aMeshName << "')";
2398   
2399   // check names of groups
2400   checkGroupNames();
2401
2402   TPythonDump() << _this() << ".ExportToMEDX( r'"
2403                 << file << "', " << auto_groups << ", " << theVersion << ", " << overwrite << " )";
2404
2405   _impl->ExportMED( file, aMeshName, auto_groups, theVersion );
2406 }
2407
2408 void SMESH_Mesh_i::ExportToMED (const char* file,
2409                                 CORBA::Boolean auto_groups,
2410                                 SMESH::MED_VERSION theVersion)
2411   throw(SALOME::SALOME_Exception)
2412 {
2413   ExportToMEDX(file,auto_groups,theVersion,true);
2414 }
2415
2416 void SMESH_Mesh_i::ExportMED (const char* file,
2417                               CORBA::Boolean auto_groups)
2418   throw(SALOME::SALOME_Exception)
2419 {
2420   ExportToMEDX(file,auto_groups,SMESH::MED_V2_1,true);
2421 }
2422
2423 void SMESH_Mesh_i::ExportDAT (const char *file)
2424   throw(SALOME::SALOME_Exception)
2425 {
2426   Unexpect aCatch(SALOME_SalomeException);
2427
2428   // Update Python script
2429   // check names of groups
2430   checkGroupNames();
2431   TPythonDump() << _this() << ".ExportDAT( r'" << file << "' )";
2432
2433   // Perform Export
2434   PrepareForWriting(file);
2435   _impl->ExportDAT(file);
2436 }
2437
2438 void SMESH_Mesh_i::ExportUNV (const char *file)
2439   throw(SALOME::SALOME_Exception)
2440 {
2441   Unexpect aCatch(SALOME_SalomeException);
2442
2443   // Update Python script
2444   // check names of groups
2445   checkGroupNames();
2446   TPythonDump() << _this() << ".ExportUNV( r'" << file << "' )";
2447
2448   // Perform Export
2449   PrepareForWriting(file);
2450   _impl->ExportUNV(file);
2451 }
2452
2453 void SMESH_Mesh_i::ExportSTL (const char *file, const bool isascii)
2454   throw(SALOME::SALOME_Exception)
2455 {
2456   Unexpect aCatch(SALOME_SalomeException);
2457
2458   // Update Python script
2459   // check names of groups
2460   checkGroupNames();
2461   TPythonDump() << _this() << ".ExportSTL( r'" << file << "', " << isascii << " )";
2462
2463   // Perform Export
2464   PrepareForWriting(file);
2465   _impl->ExportSTL(file, isascii);
2466 }
2467
2468 //=============================================================================
2469 /*!
2470  *
2471  */
2472 //=============================================================================
2473
2474 SALOME_MED::MESH_ptr SMESH_Mesh_i::GetMEDMesh()throw(SALOME::SALOME_Exception)
2475 {
2476   Unexpect aCatch(SALOME_SalomeException);
2477   SMESH_MEDMesh_i *aMedMesh = new SMESH_MEDMesh_i(this);
2478   SALOME_MED::MESH_var aMesh = aMedMesh->_this();
2479   return aMesh._retn();
2480 }
2481
2482 //=============================================================================
2483 /*!
2484  *
2485  */
2486 //=============================================================================
2487 CORBA::Long SMESH_Mesh_i::NbNodes()throw(SALOME::SALOME_Exception)
2488 {
2489   Unexpect aCatch(SALOME_SalomeException);
2490   return _impl->NbNodes();
2491 }
2492
2493 //=============================================================================
2494 /*!
2495  *
2496  */
2497 //=============================================================================
2498 CORBA::Long SMESH_Mesh_i::NbElements()throw (SALOME::SALOME_Exception)
2499 {
2500   Unexpect aCatch(SALOME_SalomeException);
2501   return Nb0DElements() + NbEdges() + NbFaces() + NbVolumes();
2502 }
2503
2504 //=============================================================================
2505 /*!
2506  *
2507  */
2508 //=============================================================================
2509 CORBA::Long SMESH_Mesh_i::Nb0DElements()throw (SALOME::SALOME_Exception)
2510 {
2511   Unexpect aCatch(SALOME_SalomeException);
2512   return _impl->Nb0DElements();
2513 }
2514
2515 //=============================================================================
2516 /*!
2517  *
2518  */
2519 //=============================================================================
2520 CORBA::Long SMESH_Mesh_i::NbEdges()throw(SALOME::SALOME_Exception)
2521 {
2522   Unexpect aCatch(SALOME_SalomeException);
2523   return _impl->NbEdges();
2524 }
2525
2526 CORBA::Long SMESH_Mesh_i::NbEdgesOfOrder(SMESH::ElementOrder order)
2527   throw(SALOME::SALOME_Exception)
2528 {
2529   Unexpect aCatch(SALOME_SalomeException);
2530   return _impl->NbEdges( (SMDSAbs_ElementOrder) order);
2531 }
2532
2533 //=============================================================================
2534 /*!
2535  *
2536  */
2537 //=============================================================================
2538 CORBA::Long SMESH_Mesh_i::NbFaces()throw(SALOME::SALOME_Exception)
2539 {
2540   Unexpect aCatch(SALOME_SalomeException);
2541   return _impl->NbFaces();
2542 }
2543
2544 CORBA::Long SMESH_Mesh_i::NbTriangles()throw(SALOME::SALOME_Exception)
2545 {
2546   Unexpect aCatch(SALOME_SalomeException);
2547   return _impl->NbTriangles();
2548 }
2549
2550 CORBA::Long SMESH_Mesh_i::NbQuadrangles()throw(SALOME::SALOME_Exception)
2551 {
2552   Unexpect aCatch(SALOME_SalomeException);
2553   return _impl->NbQuadrangles();
2554 }
2555
2556 CORBA::Long SMESH_Mesh_i::NbPolygons()throw(SALOME::SALOME_Exception)
2557 {
2558   Unexpect aCatch(SALOME_SalomeException);
2559   return _impl->NbPolygons();
2560 }
2561
2562 CORBA::Long SMESH_Mesh_i::NbFacesOfOrder(SMESH::ElementOrder order)
2563   throw(SALOME::SALOME_Exception)
2564 {
2565   Unexpect aCatch(SALOME_SalomeException);
2566   return _impl->NbFaces( (SMDSAbs_ElementOrder) order);
2567 }
2568
2569 CORBA::Long SMESH_Mesh_i::NbTrianglesOfOrder(SMESH::ElementOrder order)
2570   throw(SALOME::SALOME_Exception)
2571 {
2572   Unexpect aCatch(SALOME_SalomeException);
2573   return _impl->NbTriangles( (SMDSAbs_ElementOrder) order);
2574 }
2575
2576 CORBA::Long SMESH_Mesh_i::NbQuadranglesOfOrder(SMESH::ElementOrder order)
2577   throw(SALOME::SALOME_Exception)
2578 {
2579   Unexpect aCatch(SALOME_SalomeException);
2580   return _impl->NbQuadrangles( (SMDSAbs_ElementOrder) order);
2581 }
2582
2583 //=============================================================================
2584 /*!
2585  *
2586  */
2587 //=============================================================================
2588 CORBA::Long SMESH_Mesh_i::NbVolumes()throw(SALOME::SALOME_Exception)
2589 {
2590   Unexpect aCatch(SALOME_SalomeException);
2591   return _impl->NbVolumes();
2592 }
2593
2594 CORBA::Long SMESH_Mesh_i::NbTetras()throw(SALOME::SALOME_Exception)
2595 {
2596   Unexpect aCatch(SALOME_SalomeException);
2597   return _impl->NbTetras();
2598 }
2599
2600 CORBA::Long SMESH_Mesh_i::NbHexas()throw(SALOME::SALOME_Exception)
2601 {
2602   Unexpect aCatch(SALOME_SalomeException);
2603   return _impl->NbHexas();
2604 }
2605
2606 CORBA::Long SMESH_Mesh_i::NbPyramids()throw(SALOME::SALOME_Exception)
2607 {
2608   Unexpect aCatch(SALOME_SalomeException);
2609   return _impl->NbPyramids();
2610 }
2611
2612 CORBA::Long SMESH_Mesh_i::NbPrisms()throw(SALOME::SALOME_Exception)
2613 {
2614   Unexpect aCatch(SALOME_SalomeException);
2615   return _impl->NbPrisms();
2616 }
2617
2618 CORBA::Long SMESH_Mesh_i::NbPolyhedrons()throw(SALOME::SALOME_Exception)
2619 {
2620   Unexpect aCatch(SALOME_SalomeException);
2621   return _impl->NbPolyhedrons();
2622 }
2623
2624 CORBA::Long SMESH_Mesh_i::NbVolumesOfOrder(SMESH::ElementOrder order)
2625   throw(SALOME::SALOME_Exception)
2626 {
2627   Unexpect aCatch(SALOME_SalomeException);
2628   return _impl->NbVolumes( (SMDSAbs_ElementOrder) order);
2629 }
2630
2631 CORBA::Long SMESH_Mesh_i::NbTetrasOfOrder(SMESH::ElementOrder order)
2632   throw(SALOME::SALOME_Exception)
2633 {
2634   Unexpect aCatch(SALOME_SalomeException);
2635   return _impl->NbTetras( (SMDSAbs_ElementOrder) order);
2636 }
2637
2638 CORBA::Long SMESH_Mesh_i::NbHexasOfOrder(SMESH::ElementOrder order)
2639   throw(SALOME::SALOME_Exception)
2640 {
2641   Unexpect aCatch(SALOME_SalomeException);
2642   return _impl->NbHexas( (SMDSAbs_ElementOrder) order);
2643 }
2644
2645 CORBA::Long SMESH_Mesh_i::NbPyramidsOfOrder(SMESH::ElementOrder order)
2646   throw(SALOME::SALOME_Exception)
2647 {
2648   Unexpect aCatch(SALOME_SalomeException);
2649   return _impl->NbPyramids( (SMDSAbs_ElementOrder) order);
2650 }
2651
2652 CORBA::Long SMESH_Mesh_i::NbPrismsOfOrder(SMESH::ElementOrder order)
2653   throw(SALOME::SALOME_Exception)
2654 {
2655   Unexpect aCatch(SALOME_SalomeException);
2656   return _impl->NbPrisms( (SMDSAbs_ElementOrder) order);
2657 }
2658
2659 //=============================================================================
2660 /*!
2661  *
2662  */
2663 //=============================================================================
2664 CORBA::Long SMESH_Mesh_i::NbSubMesh()throw(SALOME::SALOME_Exception)
2665 {
2666   Unexpect aCatch(SALOME_SalomeException);
2667   return _mapSubMesh_i.size();
2668 }
2669
2670 //=============================================================================
2671 /*!
2672  *
2673  */
2674 //=============================================================================
2675 char* SMESH_Mesh_i::Dump()
2676 {
2677   ostringstream os;
2678   _impl->Dump( os );
2679   return CORBA::string_dup( os.str().c_str() );
2680 }
2681
2682 //=============================================================================
2683 /*!
2684  *
2685  */
2686 //=============================================================================
2687 SMESH::long_array* SMESH_Mesh_i::GetIDs()
2688 {
2689 //   SMESH::long_array_var aResult = new SMESH::long_array();
2690 //   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
2691 //   int aMinId = aSMESHDS_Mesh->MinElementID();
2692 //   int aMaxId =  aSMESHDS_Mesh->MaxElementID();
2693
2694 //   aResult->length(aMaxId - aMinId + 1);
2695
2696 //   for (int i = 0, id = aMinId; id <= aMaxId; id++  )
2697 //     aResult[i++] = id;
2698
2699 //   return aResult._retn();
2700   // PAL12398
2701   return GetElementsId();
2702 }
2703
2704 //=============================================================================
2705 /*!
2706  *
2707  */
2708 //=============================================================================
2709
2710 SMESH::long_array* SMESH_Mesh_i::GetElementsId()
2711      throw (SALOME::SALOME_Exception)
2712 {
2713   Unexpect aCatch(SALOME_SalomeException);
2714   MESSAGE("SMESH_Mesh_i::GetElementsId");
2715   SMESH::long_array_var aResult = new SMESH::long_array();
2716   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
2717
2718   if ( aSMESHDS_Mesh == NULL )
2719     return aResult._retn();
2720
2721   long nbElements = NbElements();
2722   aResult->length( nbElements );
2723   SMDS_ElemIteratorPtr anIt = aSMESHDS_Mesh->elementsIterator();
2724   for ( int i = 0, n = nbElements; i < n && anIt->more(); i++ )
2725     aResult[i] = anIt->next()->GetID();
2726
2727   return aResult._retn();
2728 }
2729
2730
2731 //=============================================================================
2732 /*!
2733  *
2734  */
2735 //=============================================================================
2736
2737 SMESH::long_array* SMESH_Mesh_i::GetElementsByType( SMESH::ElementType theElemType )
2738     throw (SALOME::SALOME_Exception)
2739 {
2740   Unexpect aCatch(SALOME_SalomeException);
2741   MESSAGE("SMESH_subMesh_i::GetElementsByType");
2742   SMESH::long_array_var aResult = new SMESH::long_array();
2743   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
2744
2745   if ( aSMESHDS_Mesh == NULL )
2746     return aResult._retn();
2747
2748   long nbElements = NbElements();
2749
2750   // No sense in returning ids of elements along with ids of nodes:
2751   // when theElemType == SMESH::ALL, return node ids only if
2752   // there are no elements
2753   if ( theElemType == SMESH::NODE || theElemType == SMESH::ALL && nbElements == 0 )
2754     return GetNodesId();
2755
2756   aResult->length( nbElements );
2757
2758   int i = 0;
2759
2760   SMDS_ElemIteratorPtr anIt = aSMESHDS_Mesh->elementsIterator();
2761   while ( i < nbElements && anIt->more() ) {
2762     const SMDS_MeshElement* anElem = anIt->next();
2763     if ( theElemType == SMESH::ALL || anElem->GetType() == (SMDSAbs_ElementType)theElemType )
2764       aResult[i++] = anElem->GetID();
2765   }
2766
2767   aResult->length( i );
2768
2769   return aResult._retn();
2770 }
2771
2772 //=============================================================================
2773 /*!
2774  *
2775  */
2776 //=============================================================================
2777
2778 SMESH::long_array* SMESH_Mesh_i::GetNodesId()
2779   throw (SALOME::SALOME_Exception)
2780 {
2781   Unexpect aCatch(SALOME_SalomeException);
2782   MESSAGE("SMESH_subMesh_i::GetNodesId");
2783   SMESH::long_array_var aResult = new SMESH::long_array();
2784   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
2785
2786   if ( aSMESHDS_Mesh == NULL )
2787     return aResult._retn();
2788
2789   long nbNodes = NbNodes();
2790   aResult->length( nbNodes );
2791   SMDS_NodeIteratorPtr anIt = aSMESHDS_Mesh->nodesIterator();
2792   for ( int i = 0, n = nbNodes; i < n && anIt->more(); i++ )
2793     aResult[i] = anIt->next()->GetID();
2794
2795   return aResult._retn();
2796 }
2797
2798 //=============================================================================
2799 /*!
2800  *
2801  */
2802 //=============================================================================
2803
2804 SMESH::ElementType SMESH_Mesh_i::GetElementType( const CORBA::Long id, const bool iselem )
2805   throw (SALOME::SALOME_Exception)
2806 {
2807   return ( SMESH::ElementType )_impl->GetElementType( id, iselem );
2808 }
2809
2810 //=============================================================================
2811 /*!
2812  *
2813  */
2814 //=============================================================================
2815
2816 SMESH::EntityType SMESH_Mesh_i::GetElementGeomType( const CORBA::Long id )
2817   throw (SALOME::SALOME_Exception)
2818 {
2819   const SMDS_MeshElement* e = _impl->GetMeshDS()->FindElement(id);
2820   if ( !e )
2821     THROW_SALOME_CORBA_EXCEPTION( "invalid element id", SALOME::BAD_PARAM );
2822
2823   return ( SMESH::EntityType ) e->GetEntityType();
2824 }
2825
2826 //=============================================================================
2827 /*!
2828  * Returns ID of elements for given submesh
2829  */
2830 //=============================================================================
2831 SMESH::long_array* SMESH_Mesh_i::GetSubMeshElementsId(const CORBA::Long ShapeID)
2832      throw (SALOME::SALOME_Exception)
2833 {
2834   SMESH::long_array_var aResult = new SMESH::long_array();
2835
2836   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
2837   if(!SM) return aResult._retn();
2838
2839   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
2840   if(!SDSM) return aResult._retn();
2841
2842   aResult->length(SDSM->NbElements());
2843
2844   SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
2845   int i = 0;
2846   while ( eIt->more() ) {
2847     aResult[i++] = eIt->next()->GetID();
2848   }
2849
2850   return aResult._retn();
2851 }
2852
2853
2854 //=============================================================================
2855 /*!
2856  * Returns ID of nodes for given submesh
2857  * If param all==true - returns all nodes, else -
2858  * returns only nodes on shapes.
2859  */
2860 //=============================================================================
2861 SMESH::long_array* SMESH_Mesh_i::GetSubMeshNodesId(const CORBA::Long ShapeID, CORBA::Boolean all)
2862      throw (SALOME::SALOME_Exception)
2863 {
2864   SMESH::long_array_var aResult = new SMESH::long_array();
2865
2866   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
2867   if(!SM) return aResult._retn();
2868
2869   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
2870   if(!SDSM) return aResult._retn();
2871
2872   set<int> theElems;
2873   if( !all || (SDSM->NbElements()==0) ) { // internal nodes or vertex submesh
2874     SMDS_NodeIteratorPtr nIt = SDSM->GetNodes();
2875     while ( nIt->more() ) {
2876       const SMDS_MeshNode* elem = nIt->next();
2877       theElems.insert( elem->GetID() );
2878     }
2879   }
2880   else { // all nodes of submesh elements
2881     SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
2882     while ( eIt->more() ) {
2883       const SMDS_MeshElement* anElem = eIt->next();
2884       SMDS_ElemIteratorPtr nIt = anElem->nodesIterator();
2885       while ( nIt->more() ) {
2886         const SMDS_MeshElement* elem = nIt->next();
2887         theElems.insert( elem->GetID() );
2888       }
2889     }
2890   }
2891
2892   aResult->length(theElems.size());
2893   set<int>::iterator itElem;
2894   int i = 0;
2895   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
2896     aResult[i++] = *itElem;
2897
2898   return aResult._retn();
2899 }
2900   
2901
2902 //=============================================================================
2903 /*!
2904  * Returns type of elements for given submesh
2905  */
2906 //=============================================================================
2907 SMESH::ElementType SMESH_Mesh_i::GetSubMeshElementType(const CORBA::Long ShapeID)
2908      throw (SALOME::SALOME_Exception)
2909 {
2910   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
2911   if(!SM) return SMESH::ALL;
2912
2913   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
2914   if(!SDSM) return SMESH::ALL;
2915
2916   if(SDSM->NbElements()==0)
2917     return (SM->GetSubShape().ShapeType() == TopAbs_VERTEX) ? SMESH::NODE : SMESH::ALL;
2918
2919   SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
2920   const SMDS_MeshElement* anElem = eIt->next();
2921   return ( SMESH::ElementType ) anElem->GetType();
2922 }
2923   
2924
2925 //=============================================================================
2926 /*!
2927  *
2928  */
2929 //=============================================================================
2930
2931 CORBA::LongLong SMESH_Mesh_i::GetMeshPtr()
2932 {
2933   CORBA::LongLong pointeur = CORBA::LongLong(_impl);
2934   if ( MYDEBUG )
2935     MESSAGE("CORBA::LongLong SMESH_Mesh_i::GetMeshPtr() "<<pointeur);
2936   return pointeur;
2937 }
2938
2939
2940 //=============================================================================
2941 /*!
2942  * Get XYZ coordinates of node as list of double
2943  * If there is not node for given ID - returns empty list
2944  */
2945 //=============================================================================
2946
2947 SMESH::double_array* SMESH_Mesh_i::GetNodeXYZ(const CORBA::Long id)
2948 {
2949   SMESH::double_array_var aResult = new SMESH::double_array();
2950   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
2951   if ( aSMESHDS_Mesh == NULL )
2952     return aResult._retn();
2953
2954   // find node
2955   const SMDS_MeshNode* aNode = aSMESHDS_Mesh->FindNode(id);
2956   if(!aNode)
2957     return aResult._retn();
2958
2959   // add coordinates
2960   aResult->length(3);
2961   aResult[0] = aNode->X();
2962   aResult[1] = aNode->Y();
2963   aResult[2] = aNode->Z();
2964   return aResult._retn();
2965 }
2966
2967
2968 //=============================================================================
2969 /*!
2970  * For given node returns list of IDs of inverse elements
2971  * If there is not node for given ID - returns empty list
2972  */
2973 //=============================================================================
2974
2975 SMESH::long_array* SMESH_Mesh_i::GetNodeInverseElements(const CORBA::Long id)
2976 {
2977   SMESH::long_array_var aResult = new SMESH::long_array();
2978   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
2979   if ( aSMESHDS_Mesh == NULL )
2980     return aResult._retn();
2981
2982   // find node
2983   const SMDS_MeshNode* aNode = aSMESHDS_Mesh->FindNode(id);
2984   if(!aNode)
2985     return aResult._retn();
2986
2987   // find inverse elements
2988   SMDS_ElemIteratorPtr eIt = aNode->GetInverseElementIterator();
2989   TColStd_SequenceOfInteger IDs;
2990   while(eIt->more()) {
2991     const SMDS_MeshElement* elem = eIt->next();
2992     IDs.Append(elem->GetID());
2993   }
2994   if(IDs.Length()>0) {
2995     aResult->length(IDs.Length());
2996     int i = 1;
2997     for(; i<=IDs.Length(); i++) {
2998       aResult[i-1] = IDs.Value(i);
2999     }
3000   }
3001   return aResult._retn();
3002 }
3003
3004 //=============================================================================
3005 /*!
3006  * \brief Return position of a node on shape
3007  */
3008 //=============================================================================
3009
3010 SMESH::NodePosition* SMESH_Mesh_i::GetNodePosition(CORBA::Long NodeID)
3011 {
3012   SMESH::NodePosition* aNodePosition = new SMESH::NodePosition();
3013   aNodePosition->shapeID = 0;
3014   aNodePosition->shapeType = GEOM::SHAPE;
3015
3016   SMESHDS_Mesh* mesh = _impl->GetMeshDS();
3017   if ( !mesh ) return aNodePosition;
3018
3019   if ( const SMDS_MeshNode* aNode = mesh->FindNode(NodeID) )
3020   {
3021     if ( SMDS_PositionPtr pos = aNode->GetPosition() )
3022     {
3023       aNodePosition->shapeID = pos->GetShapeId();
3024       switch ( pos->GetTypeOfPosition() ) {
3025       case SMDS_TOP_EDGE:
3026         aNodePosition->shapeType = GEOM::EDGE;
3027         aNodePosition->params.length(1);
3028         aNodePosition->params[0] =
3029           static_cast<SMDS_EdgePosition*>( pos.get() )->GetUParameter();
3030         break;
3031       case SMDS_TOP_FACE:
3032         aNodePosition->shapeType = GEOM::FACE;
3033         aNodePosition->params.length(2);
3034         aNodePosition->params[0] =
3035           static_cast<SMDS_FacePosition*>( pos.get() )->GetUParameter();
3036         aNodePosition->params[1] =
3037           static_cast<SMDS_FacePosition*>( pos.get() )->GetVParameter();
3038         break;
3039       case SMDS_TOP_VERTEX:
3040         aNodePosition->shapeType = GEOM::VERTEX;
3041         break;
3042       case SMDS_TOP_3DSPACE:
3043         if ( TopExp_Explorer(_impl->GetShapeToMesh(), TopAbs_SOLID).More() )
3044           aNodePosition->shapeType = GEOM::SOLID;
3045         else if ( TopExp_Explorer(_impl->GetShapeToMesh(), TopAbs_SHELL).More() )
3046           aNodePosition->shapeType = GEOM::SHELL;
3047         break;
3048       default:;
3049       }
3050     }
3051   }
3052   return aNodePosition;
3053 }
3054
3055 //=============================================================================
3056 /*!
3057  * If given element is node returns IDs of shape from position
3058  * If there is not node for given ID - returns -1
3059  */
3060 //=============================================================================
3061
3062 CORBA::Long SMESH_Mesh_i::GetShapeID(const CORBA::Long id)
3063 {
3064   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
3065   if ( aSMESHDS_Mesh == NULL )
3066     return -1;
3067
3068   // try to find node
3069   const SMDS_MeshNode* aNode = aSMESHDS_Mesh->FindNode(id);
3070   if(aNode) {
3071     SMDS_PositionPtr pos = aNode->GetPosition();
3072     if(!pos)
3073       return -1;
3074     else
3075       return pos->GetShapeId();
3076   }
3077
3078   return -1;
3079 }
3080
3081
3082 //=============================================================================
3083 /*!
3084  * For given element returns ID of result shape after 
3085  * ::FindShape() from SMESH_MeshEditor
3086  * If there is not element for given ID - returns -1
3087  */
3088 //=============================================================================
3089
3090 CORBA::Long SMESH_Mesh_i::GetShapeIDForElem(const CORBA::Long id)
3091 {
3092   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
3093   if ( aSMESHDS_Mesh == NULL )
3094     return -1;
3095
3096   // try to find element
3097   const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id);
3098   if(!elem)
3099     return -1;
3100
3101   //SMESH::SMESH_MeshEditor_var aMeshEditor = SMESH_Mesh_i::GetMeshEditor();
3102   ::SMESH_MeshEditor aMeshEditor(_impl);
3103   int index = aMeshEditor.FindShape( elem );
3104   if(index>0)
3105     return index;
3106
3107   return -1;
3108 }
3109
3110
3111 //=============================================================================
3112 /*!
3113  * Returns number of nodes for given element
3114  * If there is not element for given ID - returns -1
3115  */
3116 //=============================================================================
3117
3118 CORBA::Long SMESH_Mesh_i::GetElemNbNodes(const CORBA::Long id)
3119 {
3120   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
3121   if ( aSMESHDS_Mesh == NULL ) return -1;
3122   // try to find element
3123   const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id);
3124   if(!elem) return -1;
3125   return elem->NbNodes();
3126 }
3127
3128
3129 //=============================================================================
3130 /*!
3131  * Returns ID of node by given index for given element
3132  * If there is not element for given ID - returns -1
3133  * If there is not node for given index - returns -2
3134  */
3135 //=============================================================================
3136
3137 CORBA::Long SMESH_Mesh_i::GetElemNode(const CORBA::Long id, const CORBA::Long index)
3138 {
3139   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
3140   if ( aSMESHDS_Mesh == NULL ) return -1;
3141   const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id);
3142   if(!elem) return -1;
3143   if( index>=elem->NbNodes() || index<0 ) return -1;
3144   return elem->GetNode(index)->GetID();
3145 }
3146
3147 //=============================================================================
3148 /*!
3149  * Returns IDs of nodes of given element
3150  */
3151 //=============================================================================
3152
3153 SMESH::long_array* SMESH_Mesh_i::GetElemNodes(const CORBA::Long id)
3154 {
3155   SMESH::long_array_var aResult = new SMESH::long_array();
3156   if ( SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS() )
3157   {
3158     if ( const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id) )
3159     {
3160       aResult->length( elem->NbNodes() );
3161       for ( int i = 0; i < elem->NbNodes(); ++i )
3162         aResult[ i ] = elem->GetNode( i )->GetID();
3163     }
3164   }
3165   return aResult._retn();
3166 }
3167
3168 //=============================================================================
3169 /*!
3170  * Returns true if given node is medium node
3171  * in given quadratic element
3172  */
3173 //=============================================================================
3174
3175 CORBA::Boolean SMESH_Mesh_i::IsMediumNode(const CORBA::Long ide, const CORBA::Long idn)
3176 {
3177   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
3178   if ( aSMESHDS_Mesh == NULL ) return false;
3179   // try to find node
3180   const SMDS_MeshNode* aNode = aSMESHDS_Mesh->FindNode(idn);
3181   if(!aNode) return false;
3182   // try to find element
3183   const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(ide);
3184   if(!elem) return false;
3185
3186   return elem->IsMediumNode(aNode);
3187 }
3188
3189
3190 //=============================================================================
3191 /*!
3192  * Returns true if given node is medium node
3193  * in one of quadratic elements
3194  */
3195 //=============================================================================
3196
3197 CORBA::Boolean SMESH_Mesh_i::IsMediumNodeOfAnyElem(const CORBA::Long idn,
3198                                                    SMESH::ElementType theElemType)
3199 {
3200   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
3201   if ( aSMESHDS_Mesh == NULL ) return false;
3202
3203   // try to find node
3204   const SMDS_MeshNode* aNode = aSMESHDS_Mesh->FindNode(idn);
3205   if(!aNode) return false;
3206
3207   SMESH_MesherHelper aHelper( *(_impl) );
3208
3209   SMDSAbs_ElementType aType;
3210   if(theElemType==SMESH::EDGE) aType = SMDSAbs_Edge;
3211   else if(theElemType==SMESH::FACE) aType = SMDSAbs_Face;
3212   else if(theElemType==SMESH::VOLUME) aType = SMDSAbs_Volume;
3213   else aType = SMDSAbs_All;
3214
3215   return aHelper.IsMedium(aNode,aType);
3216 }
3217
3218
3219 //=============================================================================
3220 /*!
3221  * Returns number of edges for given element
3222  */
3223 //=============================================================================
3224
3225 CORBA::Long SMESH_Mesh_i::ElemNbEdges(const CORBA::Long id)
3226 {
3227   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
3228   if ( aSMESHDS_Mesh == NULL ) return -1;
3229   const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id);
3230   if(!elem) return -1;
3231   return elem->NbEdges();
3232 }
3233
3234
3235 //=============================================================================
3236 /*!
3237  * Returns number of faces for given element
3238  */
3239 //=============================================================================
3240
3241 CORBA::Long SMESH_Mesh_i::ElemNbFaces(const CORBA::Long id)
3242 {
3243   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
3244   if ( aSMESHDS_Mesh == NULL ) return -1;
3245   const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id);
3246   if(!elem) return -1;
3247   return elem->NbFaces();
3248 }
3249
3250 //=======================================================================
3251 //function : GetElemFaceNodes
3252 //purpose  : Returns nodes of given face (counted from zero) for given element.
3253 //=======================================================================
3254
3255 SMESH::long_array* SMESH_Mesh_i::GetElemFaceNodes(CORBA::Long  elemId,
3256                                                   CORBA::Short faceIndex)
3257 {
3258   SMESH::long_array_var aResult = new SMESH::long_array();
3259   if ( SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS() )
3260   {
3261     if ( const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(elemId) )
3262     {
3263       SMDS_VolumeTool vtool( elem );
3264       if ( faceIndex < vtool.NbFaces() )
3265       {
3266         aResult->length( vtool.NbFaceNodes( faceIndex ));
3267         const SMDS_MeshNode** nn = vtool.GetFaceNodes( faceIndex );
3268         for ( int i = 0; i < aResult->length(); ++i )
3269           aResult[ i ] = nn[ i ]->GetID();
3270       }
3271     }
3272   }
3273   return aResult._retn();
3274 }
3275
3276 //=======================================================================
3277 //function : FindElementByNodes
3278 //purpose  : Returns an element based on all given nodes.
3279 //=======================================================================
3280
3281 CORBA::Long SMESH_Mesh_i::FindElementByNodes(const SMESH::long_array& nodes)
3282 {
3283   CORBA::Long elemID(0);
3284   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
3285   {
3286     vector< const SMDS_MeshNode * > nn( nodes.length() );
3287     for ( int i = 0; i < nodes.length(); ++i )
3288       if ( !( nn[i] = mesh->FindNode( nodes[i] )))
3289         return elemID;
3290
3291     const SMDS_MeshElement* elem = mesh->FindElement( nn );
3292     if ( !elem && ( _impl->NbEdges( ORDER_QUADRATIC ) ||
3293                     _impl->NbFaces( ORDER_QUADRATIC ) ||
3294                     _impl->NbVolumes( ORDER_QUADRATIC )))
3295       elem = mesh->FindElement( nn, SMDSAbs_All, /*noMedium=*/true );
3296
3297     if ( elem ) elemID = CORBA::Long( elem->GetID() );
3298   }
3299   return elemID;
3300 }
3301
3302 //=============================================================================
3303 /*!
3304  * Returns true if given element is polygon
3305  */
3306 //=============================================================================
3307
3308 CORBA::Boolean SMESH_Mesh_i::IsPoly(const CORBA::Long id)
3309 {
3310   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
3311   if ( aSMESHDS_Mesh == NULL ) return false;
3312   const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id);
3313   if(!elem) return false;
3314   return elem->IsPoly();
3315 }
3316
3317
3318 //=============================================================================
3319 /*!
3320  * Returns true if given element is quadratic
3321  */
3322 //=============================================================================
3323
3324 CORBA::Boolean SMESH_Mesh_i::IsQuadratic(const CORBA::Long id)
3325 {
3326   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
3327   if ( aSMESHDS_Mesh == NULL ) return false;
3328   const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id);
3329   if(!elem) return false;
3330   return elem->IsQuadratic();
3331 }
3332
3333
3334 //=============================================================================
3335 /*!
3336  * Returns bary center for given element
3337  */
3338 //=============================================================================
3339
3340 SMESH::double_array* SMESH_Mesh_i::BaryCenter(const CORBA::Long id)
3341 {
3342   SMESH::double_array_var aResult = new SMESH::double_array();
3343   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
3344   if ( aSMESHDS_Mesh == NULL )
3345     return aResult._retn();
3346
3347   const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id);
3348   if(!elem)
3349     return aResult._retn();
3350
3351   if(elem->GetType()==SMDSAbs_Volume) {
3352     SMDS_VolumeTool aTool;
3353     if(aTool.Set(elem)) {
3354       aResult->length(3);
3355       if (!aTool.GetBaryCenter( aResult[0], aResult[1], aResult[2]) )
3356         aResult->length(0);
3357     }
3358   }
3359   else {
3360     SMDS_ElemIteratorPtr anIt = elem->nodesIterator();
3361     int nbn = 0;
3362     double x=0., y=0., z=0.;
3363     for(; anIt->more(); ) {
3364       nbn++;
3365       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(anIt->next());
3366       x += aNode->X();
3367       y += aNode->Y();
3368       z += aNode->Z();
3369     }
3370     if(nbn>0) {
3371       // add coordinates
3372       aResult->length(3);
3373       aResult[0] = x/nbn;
3374       aResult[1] = y/nbn;
3375       aResult[2] = z/nbn;
3376     }
3377   }
3378
3379   return aResult._retn();
3380 }
3381
3382
3383 //=============================================================================
3384 /*!
3385  * Create and publish group servants if any groups were imported or created anyhow
3386  */
3387 //=============================================================================
3388
3389 void SMESH_Mesh_i::CreateGroupServants() 
3390 {
3391   SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy();
3392
3393   ::SMESH_Mesh::GroupIteratorPtr groupIt = _impl->GetGroups();
3394   while ( groupIt->more() )
3395   {
3396     ::SMESH_Group* group = groupIt->next();
3397     int            anId = group->GetGroupDS()->GetID();
3398
3399     map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.find(anId);
3400     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
3401       continue;
3402
3403     SMESH_GroupBase_i* aGroupImpl;
3404     TopoDS_Shape       shape;
3405     if ( SMESHDS_GroupOnGeom* groupOnGeom =
3406          dynamic_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() ))
3407     {
3408       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
3409       shape      = groupOnGeom->GetShape();
3410     }
3411     else {
3412       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
3413     }
3414
3415     // To ensure correct mapping of servant and correct reference counting in GenericObj_i
3416     SMESH_Gen_i::GetPOA()->activate_object( aGroupImpl );
3417     aGroupImpl->Register();
3418
3419     SMESH::SMESH_GroupBase_var groupVar =
3420       SMESH::SMESH_GroupBase::_narrow( aGroupImpl->_this() );
3421     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( groupVar );
3422
3423     // register CORBA object for persistence
3424     int nextId = _gen_i->RegisterObject( groupVar );
3425     if(MYDEBUG) MESSAGE( "Add group to map with id = "<< nextId);
3426
3427     // publishing of the groups in the study
3428     if ( !aStudy->_is_nil() ) {
3429       GEOM::GEOM_Object_var shapeVar = _gen_i->ShapeToGeomObject( shape );
3430       _gen_i->PublishGroup( aStudy, _this(), groupVar, shapeVar, groupVar->GetName());
3431     }
3432   }
3433 }
3434
3435 //=============================================================================
3436 /*!
3437  * \brief Return groups cantained in _mapGroups by their IDs
3438  */
3439 //=============================================================================
3440
3441 SMESH::ListOfGroups* SMESH_Mesh_i::GetGroups(const list<int>& groupIDs) const
3442 {
3443   int nbGroups = groupIDs.size();
3444   SMESH::ListOfGroups_var aList = new SMESH::ListOfGroups();
3445   aList->length( nbGroups );
3446
3447   list<int>::const_iterator ids = groupIDs.begin();
3448   for ( nbGroups = 0; ids != groupIDs.end(); ++ids )
3449   {
3450     map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator it = _mapGroups.find( *ids );
3451     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
3452       aList[nbGroups++] = SMESH::SMESH_GroupBase::_duplicate( it->second );
3453   }
3454   aList->length( nbGroups );
3455   return aList._retn();
3456 }
3457
3458 //=============================================================================
3459 /*!
3460  * \brief Return information about imported file
3461  */
3462 //=============================================================================
3463
3464 SALOME_MED::MedFileInfo* SMESH_Mesh_i::GetMEDFileInfo()
3465 {
3466   SALOME_MED::MedFileInfo_var res( myFileInfo );
3467   if ( !res.operator->() ) {
3468     res = new SALOME_MED::MedFileInfo;
3469     res->fileName = "";
3470     res->fileSize = res->major = res->minor = res->release = -1;
3471   }
3472   return res._retn();
3473 }
3474
3475 //=============================================================================
3476 /*!
3477  * \brief Check and correct names of mesh groups
3478  */
3479 //=============================================================================
3480
3481 void SMESH_Mesh_i::checkGroupNames()
3482 {
3483   int nbGrp = NbGroups();
3484   if ( !nbGrp )
3485     return;
3486
3487   SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy();
3488   if ( aStudy->_is_nil() )
3489     return; // nothing to do
3490   
3491   SMESH::ListOfGroups* grpList = 0;
3492   // avoid dump of "GetGroups"
3493   {
3494     // store python dump into a local variable inside local scope
3495     SMESH::TPythonDump pDump; // do not delete this line of code
3496     grpList = GetGroups();
3497   }
3498
3499   for ( int gIndx = 0; gIndx < nbGrp; gIndx++ ) {
3500     SMESH::SMESH_GroupBase_ptr aGrp = (*grpList)[ gIndx ];
3501     if ( !aGrp )
3502       continue;
3503     SALOMEDS::SObject_var aGrpSO = _gen_i->ObjectToSObject( aStudy, aGrp );
3504     if ( aGrpSO->_is_nil() )
3505       continue;
3506     // correct name of the mesh group if necessary
3507     const char* guiName = aGrpSO->GetName();
3508     if ( strcmp(guiName, aGrp->GetName()) )
3509       aGrp->SetName( guiName );
3510   }
3511 }
3512
3513 //=============================================================================
3514 /*!
3515  * \brief Sets list of notebook variables used for Mesh operations separated by ":" symbol
3516  */
3517 //=============================================================================
3518 void SMESH_Mesh_i::SetParameters(const char* theParameters)
3519 {
3520   SMESH_Gen_i::GetSMESHGen()->UpdateParameters(SMESH::SMESH_Mesh::_narrow(_this()),
3521                                                CORBA::string_dup(theParameters));
3522 }
3523
3524 //=============================================================================
3525 /*!
3526  * \brief Returns list of notebook variables used for Mesh operations separated by ":" symbol
3527  */
3528 //=============================================================================
3529 char* SMESH_Mesh_i::GetParameters()
3530 {
3531   SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen();
3532   return CORBA::string_dup(gen->GetParameters(SMESH::SMESH_Mesh::_narrow(_this())));
3533 }
3534
3535 //=============================================================================
3536 /*!
3537  * \brief Returns list of notebook variables used for last Mesh operation
3538  */
3539 //=============================================================================
3540 SMESH::string_array* SMESH_Mesh_i::GetLastParameters()
3541 {
3542   SMESH::string_array_var aResult = new SMESH::string_array();
3543   SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen();
3544   if(gen) {
3545     char *aParameters = GetParameters();
3546     SALOMEDS::Study_ptr aStudy = gen->GetCurrentStudy();
3547     if(!aStudy->_is_nil()) {
3548       SALOMEDS::ListOfListOfStrings_var aSections = aStudy->ParseVariables(aParameters); 
3549       if(aSections->length() > 0) {
3550         SALOMEDS::ListOfStrings aVars = aSections[aSections->length()-1];
3551         aResult->length(aVars.length());
3552         for(int i = 0;i < aVars.length();i++)
3553           aResult[i] = CORBA::string_dup( aVars[i]);
3554       }
3555     }
3556   }
3557   return aResult._retn();
3558 }
3559
3560 //=======================================================================
3561 //function : GetTypes
3562 //purpose  : Returns types of elements it contains
3563 //=======================================================================
3564
3565 SMESH::array_of_ElementType* SMESH_Mesh_i::GetTypes()
3566 {
3567   SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType;
3568
3569   types->length( 4 );
3570   int nbTypes = 0;
3571   if (_impl->NbEdges())
3572     types[nbTypes++] = SMESH::EDGE;
3573   if (_impl->NbFaces())
3574     types[nbTypes++] = SMESH::FACE;
3575   if (_impl->NbVolumes())
3576     types[nbTypes++] = SMESH::VOLUME;
3577   if (_impl->Nb0DElements())
3578     types[nbTypes++] = SMESH::ELEM0D;
3579   types->length( nbTypes );
3580
3581   return types._retn();
3582 }
3583
3584 //=============================================================================
3585 /*!
3586  * \brief Returns statistic of mesh elements
3587  */
3588 //=============================================================================
3589 SMESH::long_array* SMESH_Mesh_i::GetMeshInfo()
3590 {
3591   SMESH::long_array_var aRes = new SMESH::long_array();
3592   aRes->length(SMESH::Entity_Last);
3593   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
3594     aRes[i] = 0;
3595   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
3596   if (!aMeshDS)
3597     return aRes._retn();
3598   const SMDS_MeshInfo& aMeshInfo = aMeshDS->GetMeshInfo();
3599   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
3600     aRes[i] = aMeshInfo.NbEntities((SMDSAbs_EntityType)i);
3601   return aRes._retn();
3602 }
3603
3604 //=============================================================================
3605 /*!
3606  * \brief Collect statistic of mesh elements given by iterator
3607  */
3608 //=============================================================================
3609 void SMESH_Mesh_i::CollectMeshInfo(const SMDS_ElemIteratorPtr theItr,
3610                                    SMESH::long_array&         theInfo)
3611 {
3612   if (!theItr) return;
3613   while (theItr->more())
3614     theInfo[ theItr->next()->GetEntityType() ]++;
3615 }
3616
3617 //=============================================================================
3618 /*!
3619  * \brief mapping of mesh dimension into shape type
3620  */
3621 //=============================================================================
3622 static TopAbs_ShapeEnum shapeTypeByDim(const int theDim)
3623 {
3624   TopAbs_ShapeEnum aType = TopAbs_SOLID;
3625   switch ( theDim ) {
3626   case 0: aType = TopAbs_VERTEX; break;
3627   case 1: aType = TopAbs_EDGE; break;
3628   case 2: aType = TopAbs_FACE; break;
3629   case 3:
3630   default:aType = TopAbs_SOLID; break;
3631   }
3632   return aType;
3633 }
3634
3635 //=============================================================================
3636 /*!
3637  * \brief Internal structure used to find concurent submeshes
3638  *
3639  * It represents a pair < submesh, concurent dimension >, where
3640  * 'concurrent dimension' is dimension of shape where the submesh can concurent
3641  *  with another submesh. In other words, it is dimension of a hypothesis assigned
3642  *  to submesh.
3643  */
3644 //=============================================================================
3645
3646 class SMESH_DimHyp
3647 {
3648  public:
3649   //! fileds
3650   int _dim;    //!< a dimension the algo can build (concurrent dimension)
3651   int _ownDim; //!< dimension of shape of _subMesh (>=_dim)
3652   TopTools_MapOfShape _shapeMap;
3653   SMESH_subMesh*      _subMesh;
3654   list<const SMESHDS_Hypothesis*> _hypothesises; //!< algo is first, then its parameters
3655
3656   //! Constructors
3657   SMESH_DimHyp(const SMESH_subMesh*  theSubMesh,
3658                const int             theDim,
3659                const TopoDS_Shape&   theShape)
3660   {
3661     _subMesh = (SMESH_subMesh*)theSubMesh;
3662     SetShape( theDim, theShape );
3663   }
3664
3665   //! set shape
3666   void SetShape(const int theDim,
3667                 const TopoDS_Shape& theShape)
3668   {
3669     _dim = theDim;
3670     _ownDim = (int)SMESH_Gen::GetShapeDim(theShape);
3671     if (_dim >= _ownDim)
3672       _shapeMap.Add( theShape );
3673     else {
3674       TopExp_Explorer anExp( theShape, shapeTypeByDim(theDim) );
3675       for( ; anExp.More(); anExp.Next() )
3676         _shapeMap.Add( anExp.Current() );
3677     }
3678   }
3679
3680   //! Check sharing of sub shapes
3681   static bool isShareSubShapes(const TopTools_MapOfShape& theToCheck,
3682                                const TopTools_MapOfShape& theToFind,
3683                                const TopAbs_ShapeEnum     theType)
3684   {
3685     bool isShared = false;
3686     TopTools_MapIteratorOfMapOfShape anItr( theToCheck );
3687     for (; !isShared && anItr.More(); anItr.Next() ) {
3688       const TopoDS_Shape aSubSh = anItr.Key();
3689       // check for case when concurrent dimensions are same
3690       isShared = theToFind.Contains( aSubSh );
3691       // check for subshape with concurrent dimension
3692       TopExp_Explorer anExp( aSubSh, theType );
3693       for ( ; !isShared && anExp.More(); anExp.Next() )
3694         isShared = theToFind.Contains( anExp.Current() );
3695     }
3696     return isShared;
3697   }
3698   
3699   //! check algorithms
3700   static bool checkAlgo(const SMESHDS_Hypothesis* theA1,
3701                         const SMESHDS_Hypothesis* theA2)
3702   {
3703     if ( theA1->GetType() == SMESHDS_Hypothesis::PARAM_ALGO ||
3704          theA2->GetType() == SMESHDS_Hypothesis::PARAM_ALGO )
3705       return false; // one of the hypothesis is not algorithm
3706     // check algorithm names (should be equal)
3707     return strcmp( theA1->GetName(), theA2->GetName() ) == 0;
3708   }
3709
3710   
3711   //! Check if subshape hypotheses are concurrent
3712   bool IsConcurrent(const SMESH_DimHyp* theOther) const
3713   {
3714     if ( _subMesh == theOther->_subMesh )
3715       return false; // same subshape - should not be
3716
3717     // if ( <own dim of either of submeshes> == <concurrent dim> &&
3718     //      any of the two submeshes is not on COMPOUND shape )
3719     //  -> no concurrency
3720     bool meIsCompound = (_subMesh->GetSubMeshDS() && _subMesh->GetSubMeshDS()->IsComplexSubmesh());
3721     bool otherIsCompound = (theOther->_subMesh->GetSubMeshDS() && theOther->_subMesh->GetSubMeshDS()->IsComplexSubmesh());
3722     if ( (_ownDim == _dim  || theOther->_ownDim == _dim ) && (!meIsCompound || !otherIsCompound))
3723       return false;
3724
3725 //     bool checkSubShape = ( _dim >= theOther->_dim )
3726 //       ? isShareSubShapes( _shapeMap, theOther->_shapeMap, shapeTypeByDim(theOther->_dim) )
3727 //       : isShareSubShapes( theOther->_shapeMap, _shapeMap, shapeTypeByDim(_dim) ) ;
3728     bool checkSubShape = isShareSubShapes( _shapeMap, theOther->_shapeMap, shapeTypeByDim(_dim));
3729     if ( !checkSubShape )
3730         return false;
3731
3732     // check algorithms to be same
3733     if (!checkAlgo( _hypothesises.front(), theOther->_hypothesises.front() ))
3734       return true; // different algorithms
3735     
3736     // check hypothesises for concurrence (skip first as algorithm)
3737     int nbSame = 0;
3738     // pointers should be same, becase it is referenes from mesh hypothesis partition
3739     list <const SMESHDS_Hypothesis*>::const_iterator hypIt = _hypothesises.begin();
3740     list <const SMESHDS_Hypothesis*>::const_iterator otheEndIt = theOther->_hypothesises.end();
3741     for ( hypIt++ /*skip first as algo*/; hypIt != _hypothesises.end(); hypIt++ )
3742       if ( find( theOther->_hypothesises.begin(), otheEndIt, *hypIt ) != otheEndIt )
3743         nbSame++;
3744     // the submeshes are concurrent if their algorithms has different parameters
3745     return nbSame != theOther->_hypothesises.size() - 1;
3746   }
3747   
3748 }; // end of SMESH_DimHyp
3749
3750 typedef list<SMESH_DimHyp*> TDimHypList;
3751
3752 static void addDimHypInstance(const int               theDim, 
3753                               const TopoDS_Shape&     theShape,
3754                               const SMESH_Algo*       theAlgo,
3755                               const SMESH_subMesh*    theSubMesh,
3756                               const list <const SMESHDS_Hypothesis*>& theHypList,
3757                               TDimHypList*            theDimHypListArr )
3758 {
3759   TDimHypList& listOfdimHyp = theDimHypListArr[theDim];
3760   if ( listOfdimHyp.empty() || listOfdimHyp.back()->_subMesh != theSubMesh ) {
3761     SMESH_DimHyp* dimHyp = new SMESH_DimHyp( theSubMesh, theDim, theShape );
3762     listOfdimHyp.push_back( dimHyp );
3763   }
3764   
3765   SMESH_DimHyp* dimHyp = listOfdimHyp.back();
3766   dimHyp->_hypothesises.push_front(theAlgo);
3767   list <const SMESHDS_Hypothesis*>::const_iterator hypIt = theHypList.begin();
3768   for( ; hypIt != theHypList.end(); hypIt++ )
3769     dimHyp->_hypothesises.push_back( *hypIt );
3770 }
3771
3772 static void findConcurrents(const SMESH_DimHyp* theDimHyp,
3773                             const TDimHypList&  theListOfDimHyp,
3774                             TListOfInt&         theListOfConcurr )
3775 {
3776   TDimHypList::const_reverse_iterator rIt = theListOfDimHyp.rbegin();
3777   for ( ; rIt != theListOfDimHyp.rend(); rIt++ ) {
3778     const SMESH_DimHyp* curDimHyp = *rIt;
3779     if ( curDimHyp == theDimHyp )
3780       break; // meet own dimHyp pointer in same dimension
3781     else if ( theDimHyp->IsConcurrent( curDimHyp ) )
3782       if ( find( theListOfConcurr.begin(),
3783                  theListOfConcurr.end(),
3784                  curDimHyp->_subMesh->GetId() ) == theListOfConcurr.end() )
3785         theListOfConcurr.push_back( curDimHyp->_subMesh->GetId() );
3786   }
3787 }
3788
3789 static void unionLists(TListOfInt&       theListOfId,
3790                        TListOfListOfInt& theListOfListOfId,
3791                        const int         theIndx )
3792 {
3793   TListOfListOfInt::iterator it = theListOfListOfId.begin();
3794   for ( int i = 0; it != theListOfListOfId.end(); it++, i++ ) {
3795     if ( i < theIndx )
3796       continue; //skip already treated lists
3797     // check if other list has any same submesh object
3798     TListOfInt& otherListOfId = *it;
3799     if ( find_first_of( theListOfId.begin(), theListOfId.end(),
3800                         otherListOfId.begin(), otherListOfId.end() ) == theListOfId.end() )
3801       continue;
3802          
3803     // union two lists (from source into target)
3804     TListOfInt::iterator it2 = otherListOfId.begin();
3805     for ( ; it2 != otherListOfId.end(); it2++ ) {
3806       if ( find( theListOfId.begin(), theListOfId.end(), (*it2) ) == theListOfId.end() )
3807         theListOfId.push_back(*it2);
3808     }
3809     // clear source list
3810     otherListOfId.clear();
3811   }
3812 }
3813
3814 //! free memory allocated for dimension-hypothesis objects
3815 static void removeDimHyps( TDimHypList* theArrOfList )
3816 {
3817   for (int i = 0; i < 4; i++ ) {
3818     TDimHypList& listOfdimHyp = theArrOfList[i];
3819     TDimHypList::const_iterator it = listOfdimHyp.begin();
3820     for ( ; it != listOfdimHyp.end(); it++ )
3821       delete (*it);
3822   }
3823 }
3824
3825 //=============================================================================
3826 /*!
3827  * \brief Return submesh objects list in meshing order
3828  */
3829 //=============================================================================
3830
3831 SMESH::submesh_array_array* SMESH_Mesh_i::GetMeshOrder()
3832 {
3833   SMESH::submesh_array_array_var aResult = new SMESH::submesh_array_array();
3834
3835   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
3836   if ( !aMeshDS )
3837     return aResult._retn();
3838   
3839   ::SMESH_Mesh& mesh = GetImpl();
3840   TListOfListOfInt anOrder = mesh.GetMeshOrder(); // is there already defined order?
3841   if ( !anOrder.size() ) {
3842
3843     // collect submeshes detecting concurrent algorithms and hypothesises
3844     TDimHypList dimHypListArr[4]; // dimHyp list for each shape dimension
3845     
3846     map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
3847     for ( ; i_sm != _mapSubMesh.end(); i_sm++ ) {
3848       ::SMESH_subMesh* sm = (*i_sm).second;
3849       // shape of submesh
3850       const TopoDS_Shape& aSubMeshShape = sm->GetSubShape();
3851       
3852       // list of assigned hypothesises
3853       const list <const SMESHDS_Hypothesis*>& hypList = mesh.GetHypothesisList(aSubMeshShape);
3854       // Find out dimensions where the submesh can be concurrent.
3855       // We define the dimensions by algo of each of hypotheses in hypList
3856       list <const SMESHDS_Hypothesis*>::const_iterator hypIt = hypList.begin();
3857       for( ; hypIt != hypList.end(); hypIt++ ) {
3858         SMESH_Algo* anAlgo = 0;
3859         const SMESH_Hypothesis* hyp = dynamic_cast<const SMESH_Hypothesis*>(*hypIt);
3860         if ( hyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO )
3861           // hyp it-self is algo
3862           anAlgo = (SMESH_Algo*)dynamic_cast<const SMESH_Algo*>(hyp);
3863         else {
3864           // try to find algorithm with help of subshapes
3865           TopExp_Explorer anExp( aSubMeshShape, shapeTypeByDim(hyp->GetDim()) );
3866           for ( ; !anAlgo && anExp.More(); anExp.Next() )
3867             anAlgo = mesh.GetGen()->GetAlgo( mesh, anExp.Current() );
3868         }
3869         if (!anAlgo)
3870           continue; // no assigned algorithm to current submesh
3871
3872         int dim = anAlgo->GetDim(); // top concurrent dimension (see comment to SMESH_DimHyp)
3873         // the submesh can concurrent at <dim> (or lower dims if !anAlgo->NeedDescretBoundary())
3874
3875         // create instance of dimension-hypothesis for found concurrent dimension(s) and algorithm
3876         for ( int j = anAlgo->NeedDescretBoundary() ? dim : 1, jn = dim; j <= jn; j++ )
3877           addDimHypInstance( j, aSubMeshShape, anAlgo, sm, hypList, dimHypListArr );
3878       }
3879     } // end iterations on submesh
3880     
3881     // iterate on created dimension-hypotheses and check for concurrents
3882     for ( int i = 0; i < 4; i++ ) {
3883       const list<SMESH_DimHyp*>& listOfDimHyp = dimHypListArr[i];
3884       // check for concurrents in own and other dimensions (step-by-step)
3885       TDimHypList::const_iterator dhIt = listOfDimHyp.begin();
3886       for ( ; dhIt != listOfDimHyp.end(); dhIt++ ) {
3887         const SMESH_DimHyp* dimHyp = *dhIt;
3888         TListOfInt listOfConcurr;
3889         // looking for concurrents and collect into own list
3890         for ( int j = i; j < 4; j++ )
3891           findConcurrents( dimHyp, dimHypListArr[j], listOfConcurr );
3892         // check if any concurrents found
3893         if ( listOfConcurr.size() > 0 ) {
3894           // add own submesh to list of concurrent
3895           listOfConcurr.push_front( dimHyp->_subMesh->GetId() );
3896           anOrder.push_back( listOfConcurr );
3897         }
3898       }
3899     }
3900     
3901     removeDimHyps(dimHypListArr);
3902     
3903     // now, minimise the number of concurrent groups
3904     // Here we assume that lists of submhes can has same submesh
3905     // in case of multi-dimension algorithms, as result
3906     //  list with common submesh have to be union into one list
3907     int listIndx = 0;
3908     TListOfListOfInt::iterator listIt = anOrder.begin();
3909     for(; listIt != anOrder.end(); listIt++, listIndx++ )
3910       unionLists( *listIt,  anOrder, listIndx + 1 );
3911   }
3912   // convert submesh ids into interface instances
3913   //  and dump command into python
3914   convertMeshOrder( anOrder, aResult, true );
3915
3916   return aResult._retn();
3917 }
3918
3919 //=============================================================================
3920 /*!
3921  * \brief find common submeshes with given submesh
3922  * \param theSubMeshList list of already collected submesh to check
3923  * \param theSubMesh given submesh to intersect with other
3924  * \param theCommonSubMeshes collected common submeshes
3925  */
3926 //=============================================================================
3927
3928 static void findCommonSubMesh
3929  (list<const SMESH_subMesh*>& theSubMeshList,
3930   const SMESH_subMesh*             theSubMesh,
3931   set<const SMESH_subMesh*>&  theCommon )
3932 {
3933   if ( !theSubMesh )
3934     return;
3935   list<const SMESH_subMesh*>::const_iterator it = theSubMeshList.begin();
3936   for ( ; it != theSubMeshList.end(); it++ )
3937     theSubMesh->FindIntersection( *it, theCommon );
3938   theSubMeshList.push_back( theSubMesh );
3939   //theCommon.insert( theSubMesh );
3940 }
3941
3942 //=============================================================================
3943 /*!
3944  * \brief Set submesh object order
3945  * \param theSubMeshArray submesh array order
3946  */
3947 //=============================================================================
3948
3949 ::CORBA::Boolean SMESH_Mesh_i::SetMeshOrder(const SMESH::submesh_array_array& theSubMeshArray)
3950 {
3951   bool res = false;
3952   ::SMESH_Mesh& mesh = GetImpl();
3953
3954   TPythonDump aPythonDump; // prevent dump of called methods
3955   aPythonDump << "isDone = " << _this() << ".SetMeshOrder( [ ";
3956
3957   TListOfListOfInt subMeshOrder;
3958   for ( int i = 0, n = theSubMeshArray.length(); i < n; i++ )
3959   {
3960     const SMESH::submesh_array& aSMArray = theSubMeshArray[i];
3961     TListOfInt subMeshIds;
3962     aPythonDump << "[ ";
3963     // Collect subMeshes which should be clear
3964     //  do it list-by-list, because modification of submesh order
3965     //  take effect between concurrent submeshes only
3966     set<const SMESH_subMesh*> subMeshToClear;
3967     list<const SMESH_subMesh*> subMeshList;
3968     for ( int j = 0, jn = aSMArray.length(); j < jn; j++ )
3969     {
3970       const SMESH::SMESH_subMesh_var subMesh = SMESH::SMESH_subMesh::_duplicate(aSMArray[j]);
3971       if ( j > 0 )
3972         aPythonDump << ", ";
3973       aPythonDump << subMesh;
3974       subMeshIds.push_back( subMesh->GetId() );
3975       // detect common parts of submeshes
3976       if ( _mapSubMesh.find(subMesh->GetId()) != _mapSubMesh.end() )
3977         findCommonSubMesh( subMeshList, _mapSubMesh[ subMesh->GetId() ], subMeshToClear );
3978     }
3979     aPythonDump << " ]";
3980     subMeshOrder.push_back( subMeshIds );
3981
3982     // clear collected submeshes
3983     set<const SMESH_subMesh*>::iterator clrIt = subMeshToClear.begin();
3984     for ( ; clrIt != subMeshToClear.end(); clrIt++ ) {
3985       SMESH_subMesh* sm = (SMESH_subMesh*)*clrIt;
3986         if ( sm )
3987           sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
3988         // ClearSubMesh( *clrIt );
3989       }
3990   }
3991   aPythonDump << " ])";
3992
3993   mesh.SetMeshOrder( subMeshOrder );
3994   res = true;
3995   
3996   return res;
3997 }
3998
3999 //=============================================================================
4000 /*!
4001  * \brief Convert submesh ids into submesh interfaces
4002  */
4003 //=============================================================================
4004
4005 void SMESH_Mesh_i::convertMeshOrder
4006 (const TListOfListOfInt& theIdsOrder,
4007  SMESH::submesh_array_array& theResOrder,
4008  const bool theIsDump)
4009 {
4010   int nbSet = theIdsOrder.size();
4011   TPythonDump aPythonDump; // prevent dump of called methods
4012   if ( theIsDump )
4013     aPythonDump << "[ ";
4014   theResOrder.length(nbSet);
4015   TListOfListOfInt::const_iterator it = theIdsOrder.begin();
4016   int listIndx = 0;
4017   for( ; it != theIdsOrder.end(); it++ ) {
4018     // translate submesh identificators into submesh objects
4019     //  takeing into account real number of concurrent lists
4020     const TListOfInt& aSubOrder = (*it);
4021     if (!aSubOrder.size())
4022       continue;
4023     if ( theIsDump )
4024       aPythonDump << "[ ";
4025     // convert shape indeces into interfaces
4026     SMESH::submesh_array_var aResSubSet = new SMESH::submesh_array();
4027     aResSubSet->length(aSubOrder.size());
4028     TListOfInt::const_iterator subIt = aSubOrder.begin();
4029     for( int j = 0; subIt != aSubOrder.end(); subIt++ ) {
4030       if ( _mapSubMeshIor.find(*subIt) == _mapSubMeshIor.end() )
4031         continue;
4032       SMESH::SMESH_subMesh_var subMesh =
4033         SMESH::SMESH_subMesh::_duplicate( _mapSubMeshIor[*subIt] );
4034       if ( theIsDump ) {
4035         if ( j > 0 )
4036           aPythonDump << ", ";
4037         aPythonDump << subMesh;
4038       }
4039       aResSubSet[ j++ ] = subMesh;
4040     }
4041     if ( theIsDump )
4042       aPythonDump << " ]";
4043     theResOrder[ listIndx++ ] = aResSubSet;
4044   }
4045   // correct number of lists
4046   theResOrder.length( listIndx );
4047
4048   if ( theIsDump ) {
4049     // finilise python dump
4050     aPythonDump << " ]";
4051     aPythonDump << " = " << _this() << ".GetMeshOrder()";
4052   }
4053 }