Salome HOME
#19765 EDF 21730 - long time to load med file file with huge amount of groups
[modules/smesh.git] / src / SMESH_I / SMESH_Mesh_i.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : SMESH_Mesh_i.cxx
23 //  Author : Paul RASCLE, EDF
24 //  Module : SMESH
25
26 #include "SMESH_Mesh_i.hxx"
27
28 #include "DriverMED_R_SMESHDS_Mesh.h"
29 #include "DriverMED_W_Field.h"
30 #include "DriverMED_W_SMESHDS_Mesh.h"
31 #include "MED_Factory.hxx"
32 #include "SMDS_LinearEdge.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_ElemIterator.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_IteratorOnIterators.hxx"
37 #include "SMDS_MeshGroup.hxx"
38 #include "SMDS_SetIterator.hxx"
39 #include "SMDS_StdIterator.hxx"
40 #include "SMDS_VolumeTool.hxx"
41 #include "SMESHDS_Command.hxx"
42 #include "SMESHDS_CommandType.hxx"
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_GroupOnGeom.hxx"
45 #include "SMESH_Controls.hxx"
46 #include "SMESH_File.hxx"
47 #include "SMESH_Filter_i.hxx"
48 #include "SMESH_Gen_i.hxx"
49 #include "SMESH_Group.hxx"
50 #include "SMESH_Group_i.hxx"
51 #include "SMESH_Mesh.hxx"
52 #include "SMESH_MeshAlgos.hxx"
53 #include "SMESH_MeshEditor.hxx"
54 #include "SMESH_MeshEditor_i.hxx"
55 #include "SMESH_MeshPartDS.hxx"
56 #include "SMESH_MesherHelper.hxx"
57 #include "SMESH_PreMeshInfo.hxx"
58 #include "SMESH_PythonDump.hxx"
59 #include "SMESH_subMesh_i.hxx"
60
61 #include <SALOMEDS_Attributes_wrap.hxx>
62 #include <SALOMEDS_wrap.hxx>
63 #include <Utils_ExceptHandlers.hxx>
64 #include <utilities.h>
65
66 #include <GEOMImpl_Types.hxx>
67 #include <GEOM_wrap.hxx>
68
69 // OCCT Includes
70 #include <BRep_Builder.hxx>
71 #include <Standard_ErrorHandler.hxx>
72 #include <TColStd_MapOfInteger.hxx>
73 #include <TopExp.hxx>
74 #include <TopExp_Explorer.hxx>
75 #include <TopTools_DataMapOfShapeShape.hxx>
76 #include <TopTools_MapIteratorOfMapOfShape.hxx>
77 #include <TopTools_MapOfShape.hxx>
78 #include <TopoDS_Compound.hxx>
79
80 // STL Includes
81 #include <algorithm>
82 #include <iostream>
83 #include <sstream>
84
85 #include <vtkUnstructuredGridWriter.h>
86
87 // to pass CORBA exception through SMESH_TRY
88 #define SMY_OWN_CATCH catch( SALOME::SALOME_Exception& se ) { throw se; }
89
90 #include "SMESH_TryCatch.hxx" // include after OCCT headers!
91
92 #ifdef _DEBUG_
93 static int MYDEBUG = 0;
94 #else
95 static int MYDEBUG = 0;
96 #endif
97
98 using namespace std;
99 using SMESH::TPythonDump;
100 using SMESH::TVar;
101
102 int SMESH_Mesh_i::_idGenerator = 0;
103
104 //=============================================================================
105 /*!
106  *  Constructor
107  */
108 //=============================================================================
109
110 SMESH_Mesh_i::SMESH_Mesh_i( PortableServer::POA_ptr thePOA,
111                             SMESH_Gen_i*            gen_i )
112 : SALOME::GenericObj_i( thePOA )
113 {
114   _impl          = NULL;
115   _gen_i         = gen_i;
116   _id            = _idGenerator++;
117   _nbInvalidHypos= -1;
118   _editor        = NULL;
119   _previewEditor = NULL;
120   _preMeshInfo   = NULL;
121   _mainShapeTick = 0;
122 }
123
124 //=============================================================================
125 /*!
126  *  Destructor
127  */
128 //=============================================================================
129
130 SMESH_Mesh_i::~SMESH_Mesh_i()
131 {
132   // destroy groups
133   map<int, SMESH::SMESH_GroupBase_ptr>::iterator itGr;
134   for (itGr = _mapGroups.begin(); itGr != _mapGroups.end(); itGr++)
135     if (SMESH_GroupBase_i* aGroup = SMESH::DownCast<SMESH_GroupBase_i*>(itGr->second))
136     {
137       aGroup->UnRegister();
138       SMESH::SMESH_GroupBase_var( itGr->second );
139     }
140   _mapGroups.clear();
141
142   // destroy submeshes
143   map<int, SMESH::SMESH_subMesh_ptr>::iterator itSM;
144   for ( itSM = _mapSubMeshIor.begin(); itSM != _mapSubMeshIor.end(); itSM++ )
145     if ( SMESH_subMesh_i* aSubMesh = SMESH::DownCast<SMESH_subMesh_i*>( itSM->second ))
146     {
147       aSubMesh->UnRegister();
148       SMESH::SMESH_subMesh_var( itSM->second );
149     }
150   _mapSubMeshIor.clear();
151
152   // destroy hypotheses. _mapHypo contains all hyps ever been assigned
153   map<int, SMESH::SMESH_Hypothesis_ptr>::iterator itH;
154   for ( itH = _mapHypo.begin(); itH != _mapHypo.end(); itH++ ) {
155     if ( SMESH_Hypothesis_i* hyp_i = SMESH::DownCast<SMESH_Hypothesis_i*>( itH->second ))
156       if ( SMESH_Hypothesis * smHyp = _impl->GetHypothesis( itH->first ))
157         if ( _impl->GetMeshDS()->IsUsedHypothesis( smHyp ))
158           hyp_i->UnRegister();
159
160     SMESH::SMESH_Hypothesis_var( itH->second ); // decref CORBA object
161   }
162   _mapHypo.clear();
163
164   // clear cached shapes if no more meshes remain; (the cache is blame,
165   // together with publishing, of spent time increasing in issue 22874)
166   if ( _impl->NbMeshes() == 1 )
167     _gen_i->GetShapeReader()->ClearClientBuffer();
168
169   delete _editor; _editor = NULL;
170   delete _previewEditor; _previewEditor = NULL;
171   delete _impl; _impl = NULL;
172   delete _preMeshInfo; _preMeshInfo = NULL;
173 }
174
175 //=============================================================================
176 /*!
177  *  SetShape
178  *
179  *  Associate <this> mesh with <theShape> and put a reference
180  *  to <theShape> into the current study;
181  *  the previous shape is substituted by the new one.
182  */
183 //=============================================================================
184
185 void SMESH_Mesh_i::SetShape( GEOM::GEOM_Object_ptr theShapeObject )
186     throw (SALOME::SALOME_Exception)
187 {
188   Unexpect aCatch(SALOME_SalomeException);
189   try {
190     _impl->ShapeToMesh( _gen_i->GeomObjectToShape( theShapeObject ));
191   }
192   catch(SALOME_Exception & S_ex) {
193     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
194   }
195   // to track changes of GEOM groups
196   SMESH::SMESH_Mesh_var mesh = _this();
197   addGeomGroupData( theShapeObject, mesh );
198   if ( !CORBA::is_nil( theShapeObject ))
199     _mainShapeTick = theShapeObject->GetTick();
200 }
201
202 //================================================================================
203 /*!
204  * \brief Return true if mesh has a shape to build a shape on
205  */
206 //================================================================================
207
208 CORBA::Boolean SMESH_Mesh_i::HasShapeToMesh()
209   throw (SALOME::SALOME_Exception)
210 {
211   Unexpect aCatch(SALOME_SalomeException);
212   bool res = false;
213   try {
214     res = _impl->HasShapeToMesh();
215   }
216   catch(SALOME_Exception & S_ex) {
217     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
218   }
219   return res;
220 }
221
222 //================================================================================
223 /*!
224  * \brief Return the shape to mesh
225  */
226 //================================================================================
227
228 GEOM::GEOM_Object_ptr SMESH_Mesh_i::GetShapeToMesh()
229   throw (SALOME::SALOME_Exception)
230 {
231   Unexpect aCatch(SALOME_SalomeException);
232   GEOM::GEOM_Object_var aShapeObj;
233   try {
234     TopoDS_Shape S = _impl->GetMeshDS()->ShapeToMesh();
235     if ( !S.IsNull() )
236     {
237       aShapeObj = _gen_i->ShapeToGeomObject( S );
238       if ( aShapeObj->_is_nil() )
239       {
240         // S was removed from GEOM_Client by newGroupShape() called by other mesh;
241         // find GEOM_Object by entry (IPAL52735)
242         list<TGeomGroupData>::iterator data = _geomGroupData.begin();
243         for ( ; data != _geomGroupData.end(); ++data )
244           if ( data->_smeshObject->_is_equivalent( _this() ))
245           {
246             SALOMEDS::SObject_wrap so = _gen_i->getStudyServant()->FindObjectID( data->_groupEntry.c_str() );
247             CORBA::Object_var     obj = _gen_i->SObjectToObject( so );
248             aShapeObj = GEOM::GEOM_Object::_narrow( obj );
249             break;
250           }
251       }
252     }
253   }
254   catch(SALOME_Exception & S_ex) {
255     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
256   }
257   return aShapeObj._retn();
258 }
259
260 //================================================================================
261 /*!
262  * \brief Return false if the mesh is not yet fully loaded from the study file
263  */
264 //================================================================================
265
266 CORBA::Boolean SMESH_Mesh_i::IsLoaded() throw (SALOME::SALOME_Exception)
267 {
268   Unexpect aCatch(SALOME_SalomeException);
269   return !_preMeshInfo;
270 }
271
272 //================================================================================
273 /*!
274  * \brief Load full mesh data from the study file
275  */
276 //================================================================================
277
278 void SMESH_Mesh_i::Load() throw (SALOME::SALOME_Exception)
279 {
280   Unexpect aCatch(SALOME_SalomeException);
281   if ( _preMeshInfo )
282     _preMeshInfo->FullLoadFromFile();
283 }
284
285 //================================================================================
286 /*!
287  * \brief Remove all nodes and elements
288  */
289 //================================================================================
290
291 void SMESH_Mesh_i::Clear() throw (SALOME::SALOME_Exception)
292 {
293   Unexpect aCatch(SALOME_SalomeException);
294   if ( _preMeshInfo )
295     _preMeshInfo->ForgetOrLoad(); // load in case if !HasShapeToMesh()
296
297   try {
298     _impl->Clear();
299     //CheckGeomGroupModif(); // issue 20145
300   }
301   catch(SALOME_Exception & S_ex) {
302     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
303   }
304
305   TPythonDump() <<  SMESH::SMESH_Mesh_var(_this()) << ".Clear()";
306
307   SMESH::SMESH_Mesh_var mesh = _this();
308   _gen_i->UpdateIcons( mesh );
309 }
310
311 //================================================================================
312 /*!
313  * \brief Remove all nodes and elements for indicated shape
314  */
315 //================================================================================
316
317 void SMESH_Mesh_i::ClearSubMesh(CORBA::Long ShapeID)
318   throw (SALOME::SALOME_Exception)
319 {
320   Unexpect aCatch(SALOME_SalomeException);
321   if ( _preMeshInfo )
322     _preMeshInfo->FullLoadFromFile();
323
324   try {
325     _impl->ClearSubMesh( ShapeID );
326   }
327   catch(SALOME_Exception & S_ex) {
328     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
329   }
330   _impl->GetMeshDS()->Modified();
331
332   TPythonDump() <<  SMESH::SMESH_Mesh_var(_this()) << ".ClearSubMesh( " << ShapeID << " )";
333 }
334
335 //=============================================================================
336 /*!
337  * Convert enum Driver_Mesh::Status to SMESH::DriverMED_ReadStatus
338  */
339 //=============================================================================
340
341 static SMESH::DriverMED_ReadStatus ConvertDriverMEDReadStatus (int theStatus)
342 {
343   SMESH::DriverMED_ReadStatus res;
344   switch (theStatus)
345   {
346   case DriverMED_R_SMESHDS_Mesh::DRS_OK:
347     res = SMESH::DRS_OK; break;
348   case DriverMED_R_SMESHDS_Mesh::DRS_EMPTY:
349     res = SMESH::DRS_EMPTY; break;
350   case DriverMED_R_SMESHDS_Mesh::DRS_WARN_RENUMBER:
351     res = SMESH::DRS_WARN_RENUMBER; break;
352   case DriverMED_R_SMESHDS_Mesh::DRS_WARN_SKIP_ELEM:
353     res = SMESH::DRS_WARN_SKIP_ELEM; break;
354   case DriverMED_R_SMESHDS_Mesh::DRS_WARN_DESCENDING:
355     res = SMESH::DRS_WARN_DESCENDING; break;
356   case DriverMED_R_SMESHDS_Mesh::DRS_FAIL:
357   default:
358     res = SMESH::DRS_FAIL; break;
359   }
360   return res;
361 }
362
363 //=============================================================================
364 /*!
365  * Convert ::SMESH_ComputeError to SMESH::ComputeError
366  */
367 //=============================================================================
368
369 static SMESH::ComputeError* ConvertComputeError( SMESH_ComputeErrorPtr errorPtr )
370 {
371   SMESH::ComputeError_var errVar = new SMESH::ComputeError();
372   errVar->subShapeID = -1;
373   errVar->hasBadMesh = false;
374
375   if ( !errorPtr || errorPtr->IsOK() )
376   {
377     errVar->code = SMESH::COMPERR_OK;
378   }
379   else
380   {
381     errVar->code    = ConvertDriverMEDReadStatus( errorPtr->myName );
382     errVar->comment = errorPtr->myComment.c_str();
383   }
384   return errVar._retn();
385 }
386
387 //=============================================================================
388 /*!
389  *  ImportMEDFile
390  *
391  *  Import mesh data from MED file
392  */
393 //=============================================================================
394
395 SMESH::DriverMED_ReadStatus
396 SMESH_Mesh_i::ImportMEDFile( const char* theFileName, const char* theMeshName )
397   throw ( SALOME::SALOME_Exception )
398 {
399   Unexpect aCatch(SALOME_SalomeException);
400   int status;
401   try {
402     status = _impl->MEDToMesh( theFileName, theMeshName );
403   }
404   catch( SALOME_Exception& S_ex ) {
405     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
406   }
407   catch ( ... ) {
408     THROW_SALOME_CORBA_EXCEPTION("ImportMEDFile(): unknown exception", SALOME::BAD_PARAM);
409   }
410
411   CreateGroupServants();
412
413   int major, minor, release;
414   major = minor = release = 0;
415   MED::GetMEDVersion(theFileName, major, minor, release);
416   _medFileInfo           = new SMESH::MedFileInfo();
417   _medFileInfo->fileName = theFileName;
418   _medFileInfo->fileSize = 0;
419   _medFileInfo->major    = major;
420   _medFileInfo->minor    = minor;
421   _medFileInfo->release  = release;
422   _medFileInfo->fileSize = SMESH_File( theFileName ).size();
423
424   return ConvertDriverMEDReadStatus(status);
425 }
426
427 //================================================================================
428 /*!
429  * \brief Import mesh data from the CGNS file
430  */
431 //================================================================================
432
433 SMESH::DriverMED_ReadStatus SMESH_Mesh_i::ImportCGNSFile( const char*  theFileName,
434                                                           const int    theMeshIndex,
435                                                           std::string& theMeshName )
436   throw ( SALOME::SALOME_Exception )
437 {
438   Unexpect aCatch(SALOME_SalomeException);
439   int status;
440   try {
441     status = _impl->CGNSToMesh( theFileName, theMeshIndex, theMeshName );
442   }
443   catch( SALOME_Exception& S_ex ) {
444     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
445   }
446   catch ( ... ) {
447     THROW_SALOME_CORBA_EXCEPTION("ImportCGNSFile(): unknown exception", SALOME::BAD_PARAM);
448   }
449
450   CreateGroupServants();
451
452   _medFileInfo           = new SMESH::MedFileInfo();
453   _medFileInfo->fileName = theFileName;
454   _medFileInfo->major    = 0;
455   _medFileInfo->minor    = 0;
456   _medFileInfo->release  = 0;
457   _medFileInfo->fileSize = SMESH_File( theFileName ).size();
458
459   return ConvertDriverMEDReadStatus(status);
460 }
461
462 //================================================================================
463 /*!
464  * \brief Return string representation of a MED file version comprising nbDigits
465  */
466 //================================================================================
467
468 char* SMESH_Mesh_i::GetVersionString(CORBA::Long minor, CORBA::Short nbDigits)
469 {
470   string ver = DriverMED_W_SMESHDS_Mesh::GetVersionString(minor,
471                                                           nbDigits);
472   return CORBA::string_dup( ver.c_str() );
473 }
474
475 //================================================================================
476 /*!
477  *  Return the list of med versions compatibles for write/append,
478  *  encoded in 10*major+minor (for instance, code for med 3.2.1 is 32)
479  */
480 //================================================================================
481
482 SMESH::long_array* SMESH_Mesh_i::GetMEDVersionsCompatibleForAppend()
483 {
484   SMESH::long_array_var aResult = new SMESH::long_array();
485   std::vector<int> mvok = MED::GetMEDVersionsAppendCompatible();
486   long nbver = mvok.size();
487   aResult->length( nbver );
488   for ( int i = 0; i < nbver; i++ )
489     aResult[i] = mvok[i];
490   return aResult._retn();
491 }
492
493 //=============================================================================
494 /*!
495  *  ImportUNVFile
496  *
497  *  Import mesh data from MED file
498  */
499 //=============================================================================
500
501 int SMESH_Mesh_i::ImportUNVFile( const char* theFileName )
502   throw ( SALOME::SALOME_Exception )
503 {
504   SMESH_TRY;
505
506   // Read mesh with name = <theMeshName> into SMESH_Mesh
507   _impl->UNVToMesh( theFileName );
508
509   CreateGroupServants();
510
511   _medFileInfo           = new SMESH::MedFileInfo();
512   _medFileInfo->fileName = theFileName;
513   _medFileInfo->major    = 0;
514   _medFileInfo->minor    = 0;
515   _medFileInfo->release  = 0;
516   _medFileInfo->fileSize = SMESH_File( theFileName ).size();
517
518   SMESH_CATCH( SMESH::throwCorbaException );
519
520   return 1;
521 }
522
523 //=============================================================================
524 /*!
525  *  ImportSTLFile
526  *
527  *  Import mesh data from STL file
528  */
529 //=============================================================================
530
531 int SMESH_Mesh_i::ImportSTLFile( const char* theFileName )
532   throw ( SALOME::SALOME_Exception )
533 {
534   SMESH_TRY;
535
536   // Read mesh with name = <theMeshName> into SMESH_Mesh
537   std::string name = _impl->STLToMesh( theFileName );
538   if ( !name.empty() )
539   {
540     SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( _this() );
541     _gen_i->SetName( meshSO, name.c_str() );
542   }
543   _medFileInfo           = new SMESH::MedFileInfo();
544   _medFileInfo->fileName = theFileName;
545   _medFileInfo->major    = 0;
546   _medFileInfo->minor    = 0;
547   _medFileInfo->release  = 0;
548   _medFileInfo->fileSize = SMESH_File( theFileName ).size();
549
550   SMESH_CATCH( SMESH::throwCorbaException );
551
552   return 1;
553 }
554
555 //================================================================================
556 /*!
557  * \brief Function used in SMESH_CATCH by ImportGMFFile()
558  */
559 //================================================================================
560
561 namespace
562 {
563   SMESH_ComputeErrorPtr exceptionToComputeError(const char* excText)
564   {
565     return SMESH_ComputeError::New( Driver_Mesh::DRS_FAIL, excText );
566   }
567 }
568
569 //================================================================================
570 /*!
571  * \brief Import data from a GMF file and return an error description
572  */
573 //================================================================================
574
575 SMESH::ComputeError* SMESH_Mesh_i::ImportGMFFile( const char* theFileName,
576                                                   bool        theMakeRequiredGroups )
577   throw (SALOME::SALOME_Exception)
578 {
579   SMESH_ComputeErrorPtr error;
580
581 #undef SMESH_CAUGHT
582 #define SMESH_CAUGHT error =
583   SMESH_TRY;
584
585   error = _impl->GMFToMesh( theFileName, theMakeRequiredGroups );
586
587   _medFileInfo           = new SMESH::MedFileInfo();
588   _medFileInfo->fileName = theFileName;
589   _medFileInfo->major    = 0;
590   _medFileInfo->minor    = 0;
591   _medFileInfo->release  = 0;
592   _medFileInfo->fileSize = SMESH_File( theFileName ).size();
593
594   SMESH_CATCH( exceptionToComputeError );
595 #undef SMESH_CAUGHT
596 #define SMESH_CAUGHT
597
598   CreateGroupServants();
599
600   return ConvertComputeError( error );
601 }
602
603 //=============================================================================
604 /*!
605  * \brief Convert SMESH_Hypothesis::Hypothesis_Status into SMESH::Hypothesis_Status
606  */
607 //=============================================================================
608
609 #define RETURNCASE(hyp_stat) case SMESH_Hypothesis::hyp_stat: return SMESH::hyp_stat;
610
611 SMESH::Hypothesis_Status SMESH_Mesh_i::ConvertHypothesisStatus
612                          (SMESH_Hypothesis::Hypothesis_Status theStatus)
613 {
614   switch (theStatus) {
615   RETURNCASE( HYP_OK            );
616   RETURNCASE( HYP_MISSING       );
617   RETURNCASE( HYP_CONCURRENT    );
618   RETURNCASE( HYP_BAD_PARAMETER );
619   RETURNCASE( HYP_HIDDEN_ALGO   );
620   RETURNCASE( HYP_HIDING_ALGO   );
621   RETURNCASE( HYP_UNKNOWN_FATAL );
622   RETURNCASE( HYP_INCOMPATIBLE  );
623   RETURNCASE( HYP_NOTCONFORM    );
624   RETURNCASE( HYP_ALREADY_EXIST );
625   RETURNCASE( HYP_BAD_DIM       );
626   RETURNCASE( HYP_BAD_SUBSHAPE  );
627   RETURNCASE( HYP_BAD_GEOMETRY  );
628   RETURNCASE( HYP_NEED_SHAPE    );
629   RETURNCASE( HYP_INCOMPAT_HYPS );
630   default:;
631   }
632   return SMESH::HYP_UNKNOWN_FATAL;
633 }
634
635 //=============================================================================
636 /*!
637  *  AddHypothesis
638  *
639  *  Call internal addHypothesis() and then add a reference to <anHyp> under
640  *  the SObject actually having a reference to <aSubShape>.
641  *  NB: For this method to work, it is necessary to add a reference to sub-shape first.
642  */
643 //=============================================================================
644
645 SMESH::Hypothesis_Status
646 SMESH_Mesh_i::AddHypothesis(GEOM::GEOM_Object_ptr       aSubShape,
647                             SMESH::SMESH_Hypothesis_ptr anHyp,
648                             CORBA::String_out           anErrorText)
649   throw(SALOME::SALOME_Exception)
650 {
651   Unexpect aCatch(SALOME_SalomeException);
652   if ( _preMeshInfo )
653     _preMeshInfo->ForgetOrLoad();
654
655   const int prevNbMeshEnt = _impl->NbNodes() + _impl->GetMeshDS()->NbElements();
656
657   std::string error;
658   SMESH_Hypothesis::Hypothesis_Status status = addHypothesis( aSubShape, anHyp, &error );
659   anErrorText = error.c_str();
660
661   SMESH::SMESH_Mesh_var mesh( _this() );
662   if ( !SMESH_Hypothesis::IsStatusFatal(status) )
663   {
664     _gen_i->AddHypothesisToShape( mesh, aSubShape, anHyp );
665
666     //int newNbMeshEnt = _impl->NbNodes() + _impl->GetMeshDS()->NbElements();
667     if ( prevNbMeshEnt > 0 /*newNbMeshEnt != prevNbMeshEnt*/ )
668       _gen_i->UpdateIcons( mesh );
669   }
670   if(MYDEBUG) MESSAGE( " AddHypothesis(): status = " << status );
671
672   // Update Python script
673   TPythonDump() << "status = " << mesh << ".AddHypothesis( "
674                 << aSubShape << ", " << anHyp << " )";
675
676   return ConvertHypothesisStatus(status);
677 }
678
679 //================================================================================
680 /*!
681  * \brief Create  a sub-mesh and add a hypothesis to it
682  */
683 //================================================================================
684
685 SMESH_Hypothesis::Hypothesis_Status
686 SMESH_Mesh_i::addHypothesis(GEOM::GEOM_Object_ptr       aSubShape,
687                             SMESH::SMESH_Hypothesis_ptr anHyp,
688                             std::string*                anErrorText)
689 {
690   if(MYDEBUG) MESSAGE("addHypothesis");
691
692   if (CORBA::is_nil( aSubShape ) && HasShapeToMesh())
693     THROW_SALOME_CORBA_EXCEPTION("bad Sub-shape reference",SALOME::BAD_PARAM);
694
695   if (CORBA::is_nil( anHyp ))
696     THROW_SALOME_CORBA_EXCEPTION("bad hypothesis reference",SALOME::BAD_PARAM);
697
698   SMESH_Hypothesis::Hypothesis_Status status = SMESH_Hypothesis::HYP_OK;
699   try
700   {
701     TopoDS_Shape myLocSubShape;
702     //use PseudoShape in case if mesh has no shape
703     if(HasShapeToMesh())
704       myLocSubShape = _gen_i->GeomObjectToShape( aSubShape);
705     else
706       myLocSubShape = _impl->GetShapeToMesh();
707
708     const int hypId = anHyp->GetId();
709     std::string error;
710     status = _impl->AddHypothesis( myLocSubShape, hypId, &error );
711     if ( !SMESH_Hypothesis::IsStatusFatal(status) )
712     {
713       _mapHypo[hypId] = SMESH::SMESH_Hypothesis::_duplicate( anHyp );
714       anHyp->Register();
715       // assure there is a corresponding submesh
716       if ( !_impl->IsMainShape( myLocSubShape )) {
717         int shapeId = _impl->GetMeshDS()->ShapeToIndex( myLocSubShape );
718         if ( _mapSubMesh_i.find( shapeId ) == _mapSubMesh_i.end() )
719           SMESH::SMESH_subMesh_var( createSubMesh( aSubShape ));
720       }
721     }
722     else if ( anErrorText )
723     {
724       *anErrorText = error;
725     }
726   }
727   catch(SALOME_Exception & S_ex)
728   {
729     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
730   }
731   return status;
732 }
733
734 //================================================================================
735 /*!
736  * \brief Un-assign a hypothesis from a sub-mesh dedicate to the given sub-shape
737  */
738 //================================================================================
739
740 SMESH::Hypothesis_Status SMESH_Mesh_i::RemoveHypothesis(GEOM::GEOM_Object_ptr       aSubShape,
741                                                         SMESH::SMESH_Hypothesis_ptr anHyp)
742   throw(SALOME::SALOME_Exception)
743 {
744   Unexpect aCatch(SALOME_SalomeException);
745   if ( _preMeshInfo )
746     _preMeshInfo->ForgetOrLoad();
747
748   SMESH_Hypothesis::Hypothesis_Status status = removeHypothesis( aSubShape, anHyp );
749   SMESH::SMESH_Mesh_var mesh = _this();
750
751   if ( !SMESH_Hypothesis::IsStatusFatal(status) )
752   {
753     _gen_i->RemoveHypothesisFromShape( mesh, aSubShape, anHyp );
754     _gen_i->UpdateIcons( mesh );
755   }
756   // Update Python script
757   if(_impl->HasShapeToMesh())
758     TPythonDump() << "status = " << mesh << ".RemoveHypothesis( "
759                   << aSubShape << ", " << anHyp << " )";
760   else
761     TPythonDump() << "status = " << mesh << ".RemoveHypothesis( "
762                   << anHyp << " )";
763
764   return ConvertHypothesisStatus(status);
765 }
766
767 //=============================================================================
768 /*!
769  * \brief Un-assign a hypothesis from a sub-mesh dedicate to the given sub-shape
770  */
771 //=============================================================================
772
773 SMESH_Hypothesis::Hypothesis_Status
774 SMESH_Mesh_i::removeHypothesis(GEOM::GEOM_Object_ptr       aSubShape,
775                                SMESH::SMESH_Hypothesis_ptr anHyp)
776 {
777   if(MYDEBUG) MESSAGE("removeHypothesis()");
778
779   if (CORBA::is_nil( aSubShape ) && HasShapeToMesh())
780     THROW_SALOME_CORBA_EXCEPTION("bad Sub-shape reference", SALOME::BAD_PARAM);
781
782   if (CORBA::is_nil( anHyp ))
783     THROW_SALOME_CORBA_EXCEPTION("bad hypothesis reference", SALOME::BAD_PARAM);
784
785   if ( _preMeshInfo )
786     _preMeshInfo->ForgetOrLoad();
787
788   SMESH_Hypothesis::Hypothesis_Status status = SMESH_Hypothesis::HYP_OK;
789   try
790   {
791     TopoDS_Shape myLocSubShape;
792     //use PseudoShape in case if mesh has no shape
793     if( _impl->HasShapeToMesh() )
794       myLocSubShape = _gen_i->GeomObjectToShape( aSubShape );
795     else
796       myLocSubShape = _impl->GetShapeToMesh();
797
798     const int hypId = anHyp->GetId();
799     status = _impl->RemoveHypothesis(myLocSubShape, hypId);
800     if ( !SMESH_Hypothesis::IsStatusFatal(status) )
801     {
802       // _mapHypo.erase( hypId ); EAP: hyp can be used on many sub-shapes
803       anHyp->UnRegister();
804     }
805   }
806   catch(SALOME_Exception & S_ex)
807   {
808     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
809   }
810   return status;
811 }
812
813 //================================================================================
814 /*!
815  * \brief Return hypotheses assigned to a given sub-shape
816  */
817 //================================================================================
818
819 SMESH::ListOfHypothesis *
820 SMESH_Mesh_i::GetHypothesisList(GEOM::GEOM_Object_ptr aSubShape)
821 throw(SALOME::SALOME_Exception)
822 {
823   Unexpect aCatch(SALOME_SalomeException);
824   if (MYDEBUG) MESSAGE("GetHypothesisList");
825   if (_impl->HasShapeToMesh() && CORBA::is_nil(aSubShape))
826     THROW_SALOME_CORBA_EXCEPTION("bad Sub-shape reference", SALOME::BAD_PARAM);
827
828   SMESH::ListOfHypothesis_var aList = new SMESH::ListOfHypothesis();
829
830   try {
831     TopoDS_Shape myLocSubShape = _gen_i->GeomObjectToShape(aSubShape);
832     if ( myLocSubShape.IsNull() && !_impl->HasShapeToMesh() )
833       myLocSubShape = _impl->GetShapeToMesh();
834     const list<const SMESHDS_Hypothesis*>& aLocalList = _impl->GetHypothesisList( myLocSubShape );
835     int i = 0, n = aLocalList.size();
836     aList->length( n );
837
838     list<const SMESHDS_Hypothesis*>::const_iterator aHyp = aLocalList.begin();
839     std::map<int, SMESH::SMESH_Hypothesis_ptr>::iterator id_hypptr;
840     for ( ; i < n && aHyp != aLocalList.end(); aHyp++ )
841     {
842       id_hypptr = _mapHypo.find( (*aHyp)->GetID() );
843       if ( id_hypptr != _mapHypo.end() )
844         aList[i++] = SMESH::SMESH_Hypothesis::_narrow( id_hypptr->second );
845     }
846     aList->length( i );
847   }
848   catch(SALOME_Exception & S_ex) {
849     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
850   }
851
852   return aList._retn();
853 }
854
855 //================================================================================
856 /*!
857  * \brief Return sub-meshes
858  */
859 //================================================================================
860
861 SMESH::submesh_array* SMESH_Mesh_i::GetSubMeshes() throw (SALOME::SALOME_Exception)
862 {
863   Unexpect aCatch(SALOME_SalomeException);
864   if (MYDEBUG) MESSAGE("GetSubMeshes");
865
866   SMESH::submesh_array_var aList = new SMESH::submesh_array();
867
868   // Python Dump
869   TPythonDump aPythonDump;
870   if ( !_mapSubMeshIor.empty() )
871     aPythonDump << "[ ";
872
873   try {
874     aList->length( _mapSubMeshIor.size() );
875     int i = 0;
876     map<int, SMESH::SMESH_subMesh_ptr>::iterator it = _mapSubMeshIor.begin();
877     for ( ; it != _mapSubMeshIor.end(); it++ ) {
878       if ( CORBA::is_nil( it->second )) continue;
879       aList[i++] = SMESH::SMESH_subMesh::_duplicate( it->second );
880       // Python Dump
881       if (i > 1) aPythonDump << ", ";
882       aPythonDump << it->second;
883     }
884     aList->length( i );
885   }
886   catch(SALOME_Exception & S_ex) {
887     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
888   }
889
890   // Update Python script
891   if ( !_mapSubMeshIor.empty() )
892     aPythonDump << " ] = " << SMESH::SMESH_Mesh_var( _this() ) << ".GetSubMeshes()";
893
894   return aList._retn();
895 }
896
897 //================================================================================
898 /*!
899  * \brief Create and return a sub-mesh on the given sub-shape
900  */
901 //================================================================================
902
903 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::GetSubMesh(GEOM::GEOM_Object_ptr aSubShape,
904                                                   const char*           theName )
905      throw(SALOME::SALOME_Exception)
906 {
907   Unexpect aCatch(SALOME_SalomeException);
908   if (CORBA::is_nil(aSubShape))
909     THROW_SALOME_CORBA_EXCEPTION("bad Sub-shape reference", SALOME::BAD_PARAM);
910
911   SMESH::SMESH_subMesh_var subMesh;
912   SMESH::SMESH_Mesh_var    aMesh = _this();
913   try {
914     TopoDS_Shape myLocSubShape = _gen_i->GeomObjectToShape(aSubShape);
915
916     //Get or Create the SMESH_subMesh object implementation
917
918     TopoDS_Iterator it( myLocSubShape );
919     int   subMeshId = _impl->GetMeshDS()->ShapeToIndex( myLocSubShape );
920     bool isValidSub = ( subMeshId || _impl->GetMeshDS()->IsGroupOfSubShapes( myLocSubShape ));
921     if ( isValidSub && myLocSubShape.ShapeType() == TopAbs_COMPOUND )
922       isValidSub = !it.Value().IsSame( _impl->GetShapeToMesh() );
923     if ( !isValidSub )
924     {
925       if ( it.More() )
926         THROW_SALOME_CORBA_EXCEPTION("Not a sub-shape of the main shape", SALOME::BAD_PARAM);
927     }
928     subMesh = getSubMesh( subMeshId );
929
930     // create a new subMesh object servant if there is none for the shape
931     if ( subMesh->_is_nil() )
932       subMesh = createSubMesh( aSubShape );
933     if ( _gen_i->CanPublishInStudy( subMesh ))
934     {
935       SALOMEDS::SObject_wrap aSO =
936         _gen_i->PublishSubMesh( aMesh, subMesh, aSubShape, theName );
937       if ( !aSO->_is_nil()) {
938         // Update Python script
939         TPythonDump() << aSO << " = " << aMesh << ".GetSubMesh( "
940                       << aSubShape << ", '" << theName << "' )";
941       }
942     }
943   }
944   catch(SALOME_Exception & S_ex) {
945     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
946   }
947   return subMesh._retn();
948 }
949
950 //================================================================================
951 /*!
952  * \brief Remove a sub-mesh
953  */
954 //================================================================================
955
956 void SMESH_Mesh_i::RemoveSubMesh( SMESH::SMESH_subMesh_ptr theSubMesh )
957   throw (SALOME::SALOME_Exception)
958 {
959   SMESH_TRY;
960
961   if ( theSubMesh->_is_nil() )
962     return;
963
964   GEOM::GEOM_Object_var aSubShape;
965   // Remove submesh's SObject
966   SALOMEDS::SObject_wrap anSO = _gen_i->ObjectToSObject( theSubMesh );
967   if ( !anSO->_is_nil() ) {
968     long aTag = SMESH_Gen_i::GetRefOnShapeTag();
969     SALOMEDS::SObject_wrap anObj, aRef;
970     if ( anSO->FindSubObject( aTag, anObj.inout() ) &&
971          anObj->ReferencedObject( aRef.inout() ))
972     {
973       CORBA::Object_var obj = aRef->GetObject();
974       aSubShape = GEOM::GEOM_Object::_narrow( obj );
975     }
976     // if ( aSubShape->_is_nil() ) // not published shape (IPAL13617)
977     //   aSubShape = theSubMesh->GetSubShape();
978
979     SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
980     builder->RemoveObjectWithChildren( anSO );
981
982     // Update Python script
983     TPythonDump() << SMESH::SMESH_Mesh_var( _this() ) << ".RemoveSubMesh( " << anSO << " )";
984   }
985
986   if ( removeSubMesh( theSubMesh, aSubShape.in() ))
987     if ( _preMeshInfo )
988       _preMeshInfo->ForgetOrLoad();
989
990   SMESH_CATCH( SMESH::throwCorbaException );
991 }
992
993 //================================================================================
994 /*!
995  * \brief Create a standalone group
996  */
997 //================================================================================
998
999 SMESH::SMESH_Group_ptr SMESH_Mesh_i::CreateGroup( SMESH::ElementType theElemType,
1000                                                   const char*        theName )
1001   throw(SALOME::SALOME_Exception)
1002 {
1003   Unexpect aCatch(SALOME_SalomeException);
1004   if ( _preMeshInfo )
1005     _preMeshInfo->FullLoadFromFile();
1006
1007   SMESH::SMESH_Group_var aNewGroup =
1008     SMESH::SMESH_Group::_narrow( createGroup( theElemType, theName ));
1009
1010   if ( _gen_i->CanPublishInStudy( aNewGroup ) )
1011   {
1012     SMESH::SMESH_Mesh_var mesh = _this();
1013     SALOMEDS::SObject_wrap aSO =
1014       _gen_i->PublishGroup( mesh, aNewGroup, GEOM::GEOM_Object::_nil(), theName);
1015     if ( !aSO->_is_nil())
1016       // Update Python script
1017       TPythonDump() << aSO << " = " << mesh << ".CreateGroup( "
1018                     << theElemType << ", '" << theName << "' )";
1019   }
1020   return aNewGroup._retn();
1021 }
1022
1023 //================================================================================
1024 /*!
1025  * \brief Create a group based on the given geometry
1026  */
1027 //================================================================================
1028
1029 SMESH::SMESH_GroupOnGeom_ptr
1030 SMESH_Mesh_i::CreateGroupFromGEOM (SMESH::ElementType    theElemType,
1031                                    const char*           theName,
1032                                    GEOM::GEOM_Object_ptr theGeomObj)
1033   throw(SALOME::SALOME_Exception)
1034 {
1035   Unexpect aCatch(SALOME_SalomeException);
1036   if ( _preMeshInfo )
1037     _preMeshInfo->FullLoadFromFile();
1038
1039   SMESH::SMESH_GroupOnGeom_var aNewGroup;
1040
1041   TopoDS_Shape aShape = _gen_i->GeomObjectToShape( theGeomObj );
1042   if ( !aShape.IsNull() )
1043   {
1044     aNewGroup =
1045       SMESH::SMESH_GroupOnGeom::_narrow( createGroup( theElemType, theName, /*id=*/-1, aShape ));
1046
1047     if ( _gen_i->CanPublishInStudy( aNewGroup ) )
1048     {
1049       SMESH::SMESH_Mesh_var mesh = _this();
1050       SALOMEDS::SObject_wrap aSO =
1051         _gen_i->PublishGroup( mesh, aNewGroup, theGeomObj, theName );
1052       if ( !aSO->_is_nil())
1053         TPythonDump() << aSO << " = " << mesh << ".CreateGroupFromGEOM( "
1054                       << theElemType << ", '" << theName << "', " << theGeomObj << " )";
1055     }
1056   }
1057
1058   return aNewGroup._retn();
1059 }
1060
1061 //================================================================================
1062 /*!
1063  * \brief Creates a group whose contents is defined by filter
1064  *  \param theElemType - group type
1065  *  \param theName - group name
1066  *  \param theFilter - the filter
1067  *  \retval SMESH::SMESH_GroupOnFilter_ptr - group defined by filter
1068  */
1069 //================================================================================
1070
1071 SMESH::SMESH_GroupOnFilter_ptr
1072 SMESH_Mesh_i::CreateGroupFromFilter(SMESH::ElementType theElemType,
1073                                     const char*        theName,
1074                                     SMESH::Filter_ptr  theFilter )
1075   throw (SALOME::SALOME_Exception)
1076 {
1077   Unexpect aCatch(SALOME_SalomeException);
1078   if ( _preMeshInfo )
1079     _preMeshInfo->FullLoadFromFile();
1080
1081   if ( CORBA::is_nil( theFilter ))
1082     THROW_SALOME_CORBA_EXCEPTION("NULL filter", SALOME::BAD_PARAM);
1083
1084   SMESH_PredicatePtr predicate = SMESH_GroupOnFilter_i::GetPredicate( theFilter );
1085   if ( !predicate )
1086     THROW_SALOME_CORBA_EXCEPTION("Invalid filter", SALOME::BAD_PARAM);
1087
1088   SMESH::SMESH_GroupOnFilter_var aNewGroup = SMESH::SMESH_GroupOnFilter::_narrow
1089     ( createGroup( theElemType, theName, /*id=*/-1, TopoDS_Shape(), predicate ));
1090
1091   TPythonDump pd;
1092   if ( !aNewGroup->_is_nil() )
1093     aNewGroup->SetFilter( theFilter );
1094
1095   if ( _gen_i->CanPublishInStudy( aNewGroup ) )
1096   {
1097     SMESH::SMESH_Mesh_var mesh = _this();
1098     SALOMEDS::SObject_wrap aSO =
1099       _gen_i->PublishGroup( mesh, aNewGroup, GEOM::GEOM_Object::_nil(), theName );
1100
1101     if ( !aSO->_is_nil())
1102       pd << aSO << " = " << mesh << ".CreateGroupFromFilter( "
1103          << theElemType << ", '" << theName << "', " << theFilter << " )";
1104   }
1105   return aNewGroup._retn();
1106 }
1107
1108 //================================================================================
1109 /*!
1110  * \brief Remove a group
1111  */
1112 //================================================================================
1113
1114 void SMESH_Mesh_i::RemoveGroup( SMESH::SMESH_GroupBase_ptr theGroup )
1115   throw (SALOME::SALOME_Exception)
1116 {
1117   if ( theGroup->_is_nil() )
1118     return;
1119
1120   SMESH_TRY;
1121
1122   SMESH_GroupBase_i* aGroup = SMESH::DownCast<SMESH_GroupBase_i*>( theGroup );
1123   if ( !aGroup )
1124     return;
1125
1126   if ( aGroup->GetMeshServant() != this )
1127     THROW_SALOME_CORBA_EXCEPTION( "RemoveGroup(): group does not belong to this mesh",
1128                                   SALOME::BAD_PARAM );
1129
1130   SALOMEDS::SObject_wrap aGroupSO = _gen_i->ObjectToSObject( theGroup );
1131   if ( !aGroupSO->_is_nil() )
1132   {
1133     // Update Python script
1134     TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".RemoveGroup( " << aGroupSO << " )";
1135
1136     // Remove group's SObject
1137     SALOMEDS::StudyBuilder_var builder = SMESH_Gen_i::getStudyServant()->NewBuilder();
1138     builder->RemoveObjectWithChildren( aGroupSO );
1139   }
1140   aGroup->Modified(/*removed=*/true); // notify dependent Filter with FT_BelongToMeshGroup criterion
1141
1142   // Remove the group from SMESH data structures
1143   removeGroup( aGroup->GetLocalID() );
1144
1145   SMESH_CATCH( SMESH::throwCorbaException );
1146 }
1147
1148 //=============================================================================
1149 /*!
1150  *  Remove group with its contents
1151  */
1152 //=============================================================================
1153
1154 void SMESH_Mesh_i::RemoveGroupWithContents( SMESH::SMESH_GroupBase_ptr theGroup )
1155   throw (SALOME::SALOME_Exception)
1156 {
1157   SMESH_TRY;
1158   if ( _preMeshInfo )
1159     _preMeshInfo->FullLoadFromFile();
1160
1161   if ( theGroup->_is_nil() )
1162     return;
1163
1164   SMESH_GroupBase_i* groupImpl = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup );
1165   if ( !groupImpl || groupImpl->GetMeshServant() != this )
1166     THROW_SALOME_CORBA_EXCEPTION( "RemoveGroupWithContents(): group does not belong to this mesh",
1167                                   SALOME::BAD_PARAM);
1168
1169   vector<int> nodeIds; // to remove nodes becoming free
1170   bool isNodal = ( theGroup->GetType() == SMESH::NODE );
1171   if ( !isNodal && !theGroup->IsEmpty() )
1172   {
1173     CORBA::Long elemID = theGroup->GetID( 1 );
1174     int nbElemNodes = GetElemNbNodes( elemID );
1175     if ( nbElemNodes > 0 )
1176       nodeIds.reserve( theGroup->Size() * nbElemNodes );
1177   }
1178
1179   // Retrieve contents
1180   SMESH::SMESH_IDSource_var idSrc = SMESH::SMESH_IDSource::_narrow( theGroup );
1181   SMDS_ElemIteratorPtr     elemIt = GetElements( idSrc, theGroup->GetType() );
1182   SMDS_StdIterator< const SMDS_MeshElement*, SMDS_ElemIteratorPtr > elemBeg( elemIt ), elemEnd;
1183   std::vector< const SMDS_MeshElement* > elems( theGroup->Size() );
1184   elems.assign( elemBeg, elemEnd );
1185
1186   TPythonDump pyDump; // Suppress dump from RemoveGroup()
1187
1188   // Remove group
1189   RemoveGroup( theGroup );
1190
1191   // Remove contents
1192   for ( size_t i = 0; i < elems.size(); ++i )
1193   {
1194     // if ( !_impl->GetMeshDS()->Contains( elems[i] ))
1195     //   continue;
1196     if ( !isNodal )
1197     {
1198       for ( SMDS_ElemIteratorPtr nIt = elems[i]->nodesIterator(); nIt->more(); )
1199         nodeIds.push_back( nIt->next()->GetID() );
1200
1201       _impl->GetMeshDS()->RemoveFreeElement( elems[i], /*sm=*/0 );
1202     }
1203     else
1204     {
1205       _impl->GetMeshDS()->RemoveElement( elems[i] );
1206     }
1207   }
1208
1209   // Remove free nodes
1210   for ( size_t i = 0 ; i < nodeIds.size(); ++i )
1211     if ( const SMDS_MeshNode* n = _impl->GetMeshDS()->FindNode( nodeIds[i] ))
1212       if ( n->NbInverseElements() == 0 )
1213         _impl->GetMeshDS()->RemoveFreeNode( n, /*sm=*/0 );
1214
1215   // Update Python script (theGroup must be alive for this)
1216   pyDump << SMESH::SMESH_Mesh_var(_this())
1217          << ".RemoveGroupWithContents( " << theGroup << " )";
1218
1219   SMESH_CATCH( SMESH::throwCorbaException );
1220 }
1221
1222 //================================================================================
1223 /*!
1224  * \brief Get the list of groups existing in the mesh
1225  *  \retval SMESH::ListOfGroups * - list of groups
1226  */
1227 //================================================================================
1228
1229 SMESH::ListOfGroups * SMESH_Mesh_i::GetGroups() throw(SALOME::SALOME_Exception)
1230 {
1231   Unexpect aCatch(SALOME_SalomeException);
1232   if (MYDEBUG) MESSAGE("GetGroups");
1233
1234   SMESH::ListOfGroups_var aList = new SMESH::ListOfGroups();
1235
1236   // Python Dump
1237   TPythonDump aPythonDump;
1238   if ( !_mapGroups.empty() )
1239   {
1240     aPythonDump << "[ ";
1241     try {
1242       aList->length( _mapGroups.size() );
1243       int i = 0;
1244       map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.begin();
1245       for ( ; it != _mapGroups.end(); it++ ) {
1246         if ( CORBA::is_nil( it->second )) continue;
1247         aList[i++] = SMESH::SMESH_GroupBase::_duplicate( it->second );
1248         // Python Dump
1249         if (i > 1) aPythonDump << ", ";
1250         aPythonDump << it->second;
1251       }
1252       aList->length( i );
1253     }
1254     catch(SALOME_Exception & S_ex) {
1255       THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
1256     }
1257     aPythonDump << " ] = " << SMESH::SMESH_Mesh_var(_this()) << ".GetGroups()";
1258   }
1259   return aList._retn();
1260 }
1261
1262 //=============================================================================
1263 /*!
1264  *  Get number of groups existing in the mesh
1265  */
1266 //=============================================================================
1267
1268 CORBA::Long SMESH_Mesh_i::NbGroups() throw (SALOME::SALOME_Exception)
1269 {
1270   Unexpect aCatch(SALOME_SalomeException);
1271   return _mapGroups.size();
1272 }
1273
1274 //=============================================================================
1275 /*!
1276  * New group including all mesh elements present in initial groups is created.
1277  */
1278 //=============================================================================
1279
1280 SMESH::SMESH_Group_ptr SMESH_Mesh_i::UnionGroups( SMESH::SMESH_GroupBase_ptr theGroup1,
1281                                                   SMESH::SMESH_GroupBase_ptr theGroup2,
1282                                                   const char*                theName )
1283   throw (SALOME::SALOME_Exception)
1284 {
1285   SMESH::SMESH_Group_var aResGrp;
1286
1287   SMESH_TRY;
1288   if ( _preMeshInfo )
1289     _preMeshInfo->FullLoadFromFile();
1290
1291   if ( theGroup1->_is_nil() || theGroup2->_is_nil() )
1292     THROW_SALOME_CORBA_EXCEPTION("UnionGroups(): NULL Group",
1293                                  SALOME::BAD_PARAM);
1294   if ( theGroup1->GetType() != theGroup2->GetType() )
1295     THROW_SALOME_CORBA_EXCEPTION("UnionGroups(): different group types",
1296                                  SALOME::BAD_PARAM);
1297   TPythonDump pyDump;
1298
1299   // Create Union
1300   aResGrp = CreateGroup( theGroup1->GetType(), theName );
1301   if ( aResGrp->_is_nil() )
1302     return SMESH::SMESH_Group::_nil();
1303
1304   aResGrp->AddFrom( theGroup1 );
1305   aResGrp->AddFrom( theGroup2 );
1306
1307   // Update Python script
1308   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var(_this())
1309          << ".UnionGroups( " << theGroup1 << ", " << theGroup2 << ", '" << theName << "' )";
1310
1311   SMESH_CATCH( SMESH::throwCorbaException );
1312
1313   return aResGrp._retn();
1314 }
1315
1316 //=============================================================================
1317 /*!
1318  * \brief New group including all mesh elements present in initial groups is created.
1319  *  \param theGroups list of groups
1320  *  \param theName name of group to be created
1321  *  \return pointer to the new group
1322  */
1323 //=============================================================================
1324
1325 SMESH::SMESH_Group_ptr SMESH_Mesh_i::UnionListOfGroups(const SMESH::ListOfGroups& theGroups,
1326                                                        const char*                theName )
1327   throw (SALOME::SALOME_Exception)
1328 {
1329   SMESH::SMESH_Group_var aResGrp;
1330
1331   if ( _preMeshInfo )
1332     _preMeshInfo->FullLoadFromFile();
1333
1334   if ( !theName )
1335     return SMESH::SMESH_Group::_nil();
1336
1337   SMESH_TRY;
1338
1339   // check types
1340   SMESH::ElementType aType = SMESH::ALL;
1341   for ( int g = 0, n = theGroups.length(); g < n; g++ )
1342   {
1343     SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ];
1344     if ( CORBA::is_nil( aGrp ) )
1345       continue;
1346     if ( aType == SMESH::ALL )
1347       aType = aGrp->GetType();
1348     else if ( aType != aGrp->GetType() )
1349       THROW_SALOME_CORBA_EXCEPTION("UnionListOfGroups(): different group types",
1350                                    SALOME::BAD_PARAM);
1351   }
1352   if ( aType == SMESH::ALL )
1353     return SMESH::SMESH_Group::_nil();
1354
1355   TPythonDump pyDump;
1356
1357   // Create Union
1358   aResGrp = CreateGroup( aType, theName );
1359   if ( aResGrp->_is_nil() )
1360     return SMESH::SMESH_Group::_nil();
1361
1362   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var(_this()) << ".UnionListOfGroups([ ";
1363   for ( int g = 0, n = theGroups.length(); g < n; g++ )
1364   {
1365     SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ];
1366     if ( !CORBA::is_nil( aGrp ) )
1367     {
1368       aResGrp->AddFrom( aGrp );
1369       if ( g > 0 ) pyDump << ", ";
1370       pyDump << aGrp;
1371     }
1372   }
1373   pyDump << " ], '" << theName << "' )";
1374
1375   SMESH_CATCH( SMESH::throwCorbaException );
1376
1377   return aResGrp._retn();
1378 }
1379
1380 //=============================================================================
1381 /*!
1382  *  New group is created. All mesh elements that are
1383  *  present in both initial groups are added to the new one.
1384  */
1385 //=============================================================================
1386
1387 SMESH::SMESH_Group_ptr SMESH_Mesh_i::IntersectGroups( SMESH::SMESH_GroupBase_ptr theGroup1,
1388                                                       SMESH::SMESH_GroupBase_ptr theGroup2,
1389                                                       const char*                theName )
1390   throw (SALOME::SALOME_Exception)
1391 {
1392   SMESH::SMESH_Group_var aResGrp;
1393
1394   SMESH_TRY;
1395
1396   if ( _preMeshInfo )
1397     _preMeshInfo->FullLoadFromFile();
1398
1399   if ( theGroup1->_is_nil() || theGroup2->_is_nil() )
1400     THROW_SALOME_CORBA_EXCEPTION("IntersectGroups(): NULL Group",
1401                                  SALOME::BAD_PARAM);
1402   if ( theGroup1->GetType() != theGroup2->GetType() )
1403     THROW_SALOME_CORBA_EXCEPTION("IntersectGroups(): different group types",
1404                                  SALOME::BAD_PARAM);
1405   TPythonDump pyDump;
1406
1407   // Create Intersection
1408   aResGrp = CreateGroup( theGroup1->GetType(), theName );
1409   if ( aResGrp->_is_nil() )
1410     return aResGrp._retn();
1411
1412   SMESHDS_GroupBase* groupDS1 = 0;
1413   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup1 ))
1414     groupDS1 = grp_i->GetGroupDS();
1415
1416   SMESHDS_GroupBase* groupDS2 = 0;
1417   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup2 ))
1418     groupDS2 = grp_i->GetGroupDS();
1419
1420   SMESHDS_Group* resGroupDS = 0;
1421   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aResGrp ))
1422     resGroupDS = dynamic_cast<SMESHDS_Group*>( grp_i->GetGroupDS() );
1423
1424   if ( groupDS1 && groupDS2 && resGroupDS && !groupDS2->IsEmpty() )
1425   {
1426     SMDS_ElemIteratorPtr elemIt1 = groupDS1->GetElements();
1427     while ( elemIt1->more() )
1428     {
1429       const SMDS_MeshElement* e = elemIt1->next();
1430       if ( groupDS2->Contains( e ))
1431         resGroupDS->SMDSGroup().Add( e );
1432     }
1433   }
1434   // Update Python script
1435   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var(_this()) << ".IntersectGroups( "
1436          << theGroup1 << ", " << theGroup2 << ", '" << theName << "')";
1437
1438   SMESH_CATCH( SMESH::throwCorbaException );
1439
1440   return aResGrp._retn();
1441 }
1442
1443 //=============================================================================
1444 /*!
1445   \brief Intersect list of groups. New group is created. All mesh elements that
1446   are present in all initial groups simultaneously are added to the new one.
1447   \param theGroups list of groups
1448   \param theName name of group to be created
1449   \return pointer on the group
1450 */
1451 //=============================================================================
1452
1453 SMESH::SMESH_Group_ptr
1454 SMESH_Mesh_i::IntersectListOfGroups(const SMESH::ListOfGroups& theGroups,
1455                                     const char*                theName )
1456   throw (SALOME::SALOME_Exception)
1457 {
1458   SMESH::SMESH_Group_var aResGrp;
1459
1460   SMESH_TRY;
1461
1462   if ( _preMeshInfo )
1463     _preMeshInfo->FullLoadFromFile();
1464
1465   if ( !theName )
1466     return SMESH::SMESH_Group::_nil();
1467
1468   // check types and get SMESHDS_GroupBase's
1469   SMESH::ElementType aType = SMESH::ALL;
1470   vector< SMESHDS_GroupBase* > groupVec;
1471   for ( int g = 0, n = theGroups.length(); g < n; g++ )
1472   {
1473     SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ];
1474     if ( CORBA::is_nil( aGrp ) )
1475       continue;
1476     if ( aType == SMESH::ALL )
1477       aType = aGrp->GetType();
1478     else if ( aType != aGrp->GetType() )
1479       THROW_SALOME_CORBA_EXCEPTION("IntersectListOfGroups(): different group types",
1480                                    SALOME::BAD_PARAM);
1481
1482     if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aGrp ))
1483       if ( SMESHDS_GroupBase* grpDS = grp_i->GetGroupDS() )
1484       {
1485         if ( grpDS->IsEmpty() )
1486         {
1487           groupVec.clear();
1488           break;
1489         }
1490         groupVec.push_back( grpDS );
1491       }
1492   }
1493   if ( aType == SMESH::ALL ) // all groups are nil
1494     return SMESH::SMESH_Group::_nil();
1495
1496   TPythonDump pyDump;
1497
1498   // Create a group
1499   aResGrp = CreateGroup( aType, theName );
1500
1501   SMESHDS_Group* resGroupDS = 0;
1502   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aResGrp ))
1503     resGroupDS = dynamic_cast<SMESHDS_Group*>( grp_i->GetGroupDS() );
1504   if ( !resGroupDS || groupVec.empty() )
1505     return aResGrp._retn();
1506
1507   // Fill the group
1508   size_t i, nb = groupVec.size();
1509   SMDS_ElemIteratorPtr elemIt1 = groupVec[0]->GetElements();
1510   while ( elemIt1->more() )
1511   {
1512     const SMDS_MeshElement* e = elemIt1->next();
1513     bool inAll = true;
1514     for ( i = 1; ( i < nb && inAll ); ++i )
1515       inAll = groupVec[i]->Contains( e );
1516
1517     if ( inAll )
1518       resGroupDS->SMDSGroup().Add( e );
1519   }
1520
1521   // Update Python script
1522   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var( _this() )
1523          << ".IntersectListOfGroups( " << theGroups << ", '" << theName << "' )";
1524
1525   SMESH_CATCH( SMESH::throwCorbaException );
1526
1527   return aResGrp._retn();
1528 }
1529
1530 //=============================================================================
1531 /*!
1532  *  New group is created. All mesh elements that are present in
1533  *  a main group but is not present in a tool group are added to the new one
1534  */
1535 //=============================================================================
1536
1537 SMESH::SMESH_Group_ptr SMESH_Mesh_i::CutGroups( SMESH::SMESH_GroupBase_ptr theGroup1,
1538                                                 SMESH::SMESH_GroupBase_ptr theGroup2,
1539                                                 const char*                theName )
1540   throw (SALOME::SALOME_Exception)
1541 {
1542   SMESH::SMESH_Group_var aResGrp;
1543
1544   SMESH_TRY;
1545
1546   if ( _preMeshInfo )
1547     _preMeshInfo->FullLoadFromFile();
1548
1549   if ( theGroup1->_is_nil() || theGroup2->_is_nil() )
1550     THROW_SALOME_CORBA_EXCEPTION("CutGroups(): NULL Group",
1551                                  SALOME::BAD_PARAM);
1552   if ( theGroup1->GetType() != theGroup2->GetType() )
1553     THROW_SALOME_CORBA_EXCEPTION("CutGroups(): different group types",
1554                                  SALOME::BAD_PARAM);
1555   TPythonDump pyDump;
1556
1557   aResGrp = CreateGroup( theGroup1->GetType(), theName );
1558   if ( aResGrp->_is_nil() )
1559     return aResGrp._retn();
1560
1561   SMESHDS_GroupBase* groupDS1 = 0;
1562   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup1 ))
1563     groupDS1 = grp_i->GetGroupDS();
1564
1565   SMESHDS_GroupBase* groupDS2 = 0;
1566   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup2 ))
1567     groupDS2 = grp_i->GetGroupDS();
1568
1569   SMESHDS_Group* resGroupDS = 0;
1570   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aResGrp ))
1571     resGroupDS = dynamic_cast<SMESHDS_Group*>( grp_i->GetGroupDS() );
1572
1573   if ( groupDS1 && groupDS2 && resGroupDS )
1574   {
1575     SMDS_ElemIteratorPtr elemIt1 = groupDS1->GetElements();
1576     while ( elemIt1->more() )
1577     {
1578       const SMDS_MeshElement* e = elemIt1->next();
1579       if ( !groupDS2->Contains( e ))
1580         resGroupDS->SMDSGroup().Add( e );
1581     }
1582   }
1583   // Update Python script
1584   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var(_this()) << ".CutGroups( "
1585          << theGroup1 << ", " << theGroup2 << ", '" << theName << "')";
1586
1587   SMESH_CATCH( SMESH::throwCorbaException );
1588
1589   return aResGrp._retn();
1590 }
1591
1592 //=============================================================================
1593 /*!
1594   \brief Cut lists of groups. New group is created. All mesh elements that are
1595   present in main groups but do not present in tool groups are added to the new one
1596   \param theMainGroups list of main groups
1597   \param theToolGroups list of tool groups
1598   \param theName name of group to be created
1599   \return pointer on the group
1600 */
1601 //=============================================================================
1602
1603 SMESH::SMESH_Group_ptr
1604 SMESH_Mesh_i::CutListOfGroups(const SMESH::ListOfGroups& theMainGroups,
1605                               const SMESH::ListOfGroups& theToolGroups,
1606                               const char*                theName )
1607   throw (SALOME::SALOME_Exception)
1608 {
1609   SMESH::SMESH_Group_var aResGrp;
1610
1611   SMESH_TRY;
1612
1613   if ( _preMeshInfo )
1614     _preMeshInfo->FullLoadFromFile();
1615
1616   if ( !theName )
1617     return SMESH::SMESH_Group::_nil();
1618
1619   // check types and get SMESHDS_GroupBase's
1620   SMESH::ElementType aType = SMESH::ALL;
1621   vector< SMESHDS_GroupBase* >   toolGroupVec;
1622   vector< SMDS_ElemIteratorPtr > mainIterVec;
1623
1624   for ( int g = 0, n = theMainGroups.length(); g < n; g++ )
1625   {
1626     SMESH::SMESH_GroupBase_var aGrp = theMainGroups[ g ];
1627     if ( CORBA::is_nil( aGrp ) )
1628       continue;
1629     if ( aType == SMESH::ALL )
1630       aType = aGrp->GetType();
1631     else if ( aType != aGrp->GetType() )
1632       THROW_SALOME_CORBA_EXCEPTION("CutListOfGroups(): different group types",
1633                                    SALOME::BAD_PARAM);
1634     if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aGrp ))
1635       if ( SMESHDS_GroupBase* grpDS = grp_i->GetGroupDS() )
1636         if ( !grpDS->IsEmpty() )
1637           mainIterVec.push_back( grpDS->GetElements() );
1638   }
1639   if ( aType == SMESH::ALL ) // all main groups are nil
1640     return SMESH::SMESH_Group::_nil();
1641   if ( mainIterVec.empty() ) // all main groups are empty
1642     return aResGrp._retn();
1643
1644   for ( int g = 0, n = theToolGroups.length(); g < n; g++ )
1645   {
1646     SMESH::SMESH_GroupBase_var aGrp = theToolGroups[ g ];
1647     if ( CORBA::is_nil( aGrp ) )
1648       continue;
1649     if ( aType != aGrp->GetType() )
1650       THROW_SALOME_CORBA_EXCEPTION("CutListOfGroups(): different group types",
1651                                    SALOME::BAD_PARAM);
1652     if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aGrp ))
1653       if ( SMESHDS_GroupBase* grpDS = grp_i->GetGroupDS() )
1654         toolGroupVec.push_back( grpDS );
1655   }
1656
1657   TPythonDump pyDump;
1658
1659   // Create a group
1660   aResGrp = CreateGroup( aType, theName );
1661
1662   SMESHDS_Group* resGroupDS = 0;
1663   if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aResGrp ))
1664     resGroupDS = dynamic_cast<SMESHDS_Group*>( grp_i->GetGroupDS() );
1665   if ( !resGroupDS )
1666     return aResGrp._retn();
1667
1668   // Fill the group
1669   size_t i, nb = toolGroupVec.size();
1670   SMDS_ElemIteratorPtr mainElemIt
1671     ( new SMDS_IteratorOnIterators
1672       < const SMDS_MeshElement*, vector< SMDS_ElemIteratorPtr > >( mainIterVec ));
1673   while ( mainElemIt->more() )
1674   {
1675     const SMDS_MeshElement* e = mainElemIt->next();
1676     bool isIn = false;
1677     for ( i = 0; ( i < nb && !isIn ); ++i )
1678       isIn = toolGroupVec[i]->Contains( e );
1679
1680     if ( !isIn )
1681       resGroupDS->SMDSGroup().Add( e );
1682   }
1683
1684   // Update Python script
1685   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var( _this() )
1686          << ".CutListOfGroups( " << theMainGroups << ", "
1687          << theToolGroups << ", '" << theName << "' )";
1688
1689   SMESH_CATCH( SMESH::throwCorbaException );
1690
1691   return aResGrp._retn();
1692 }
1693
1694 namespace // functions making checks according to SMESH::NB_COMMON_NODES_ENUM
1695 {
1696   bool isAllNodesCommon(int nbChecked, int nbCommon, int nbNodes, int nbCorners,
1697                         bool & toStopChecking )
1698   {
1699     toStopChecking = ( nbCommon < nbChecked );
1700     return nbCommon == nbNodes;
1701   }
1702   bool isMainNodesCommon(int nbChecked, int nbCommon, int nbNodes, int nbCorners,
1703                          bool & toStopChecking )
1704   {
1705     toStopChecking = ( nbCommon < nbChecked || nbChecked >= nbCorners );
1706     return nbCommon == nbCorners;
1707   }
1708   bool isAtLeastOneNodeCommon(int nbChecked, int nbCommon, int nbNodes, int nbCorners,
1709                               bool & toStopChecking )
1710   {
1711     return nbCommon > 0;
1712   }
1713   bool isMajorityOfNodesCommon(int nbChecked, int nbCommon, int nbNodes, int nbCorners,
1714                                bool & toStopChecking )
1715   {
1716     return nbCommon >= (nbNodes+1) / 2;
1717   }
1718 }
1719
1720 //=============================================================================
1721 /*!
1722  * Create a group of entities basing on nodes of other groups.
1723  *  \param [in] theGroups - list of either groups, sub-meshes or filters.
1724  *  \param [in] anElemType - a type of elements to include to the new group.
1725  *  \param [in] theName - a name of the new group.
1726  *  \param [in] theNbCommonNodes - criterion of inclusion of an element to the new group.
1727  *  \param [in] theUnderlyingOnly - if \c True, an element is included to the
1728  *         new group provided that it is based on nodes of an element of \a aListOfGroups
1729  *  \return SMESH_Group - the created group
1730 */
1731 // IMP 19939, bug 22010, IMP 22635
1732 //=============================================================================
1733
1734 SMESH::SMESH_Group_ptr
1735 SMESH_Mesh_i::CreateDimGroup(const SMESH::ListOfIDSources& theGroups,
1736                              SMESH::ElementType            theElemType,
1737                              const char*                   theName,
1738                              SMESH::NB_COMMON_NODES_ENUM   theNbCommonNodes,
1739                              CORBA::Boolean                theUnderlyingOnly)
1740   throw (SALOME::SALOME_Exception)
1741 {
1742   SMESH::SMESH_Group_var aResGrp;
1743
1744   SMESH_TRY;
1745   if ( _preMeshInfo )
1746     _preMeshInfo->FullLoadFromFile();
1747
1748   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
1749
1750   if ( !theName || !aMeshDS )
1751     return SMESH::SMESH_Group::_nil();
1752
1753   SMDSAbs_ElementType anElemType = (SMDSAbs_ElementType)theElemType;
1754
1755   bool (*isToInclude)(int nbChecked, int nbCommon, int nbNodes, int nbCorners, bool & toStop);
1756   SMESH_Comment nbCoNoStr( "SMESH.");
1757   switch ( theNbCommonNodes ) {
1758   case SMESH::ALL_NODES   : isToInclude = isAllNodesCommon;        nbCoNoStr<<"ALL_NODES"   ;break;
1759   case SMESH::MAIN        : isToInclude = isMainNodesCommon;       nbCoNoStr<<"MAIN"        ;break;
1760   case SMESH::AT_LEAST_ONE: isToInclude = isAtLeastOneNodeCommon;  nbCoNoStr<<"AT_LEAST_ONE";break;
1761   case SMESH::MAJORITY    : isToInclude = isMajorityOfNodesCommon; nbCoNoStr<<"MAJORITY"    ;break;
1762   default: return aResGrp._retn();
1763   }
1764   int nbChecked, nbCommon, nbNodes, nbCorners;
1765
1766   // Create a group
1767
1768   TPythonDump pyDump;
1769
1770   aResGrp = CreateGroup( theElemType, theName );
1771   if ( aResGrp->_is_nil() )
1772     return SMESH::SMESH_Group::_nil();
1773
1774   SMESHDS_GroupBase* groupBaseDS =
1775     SMESH::DownCast<SMESH_GroupBase_i*>( aResGrp )->GetGroupDS();
1776   SMDS_MeshGroup& resGroupCore = static_cast< SMESHDS_Group* >( groupBaseDS )->SMDSGroup();
1777
1778   vector<bool> isNodeInGroups;
1779
1780   for ( int g = 0, n = theGroups.length(); g < n; g++ ) // loop on theGroups
1781   {
1782     SMESH::SMESH_IDSource_var aGrp = theGroups[ g ];
1783     if ( CORBA::is_nil( aGrp ) )
1784       continue;
1785     SMESH::SMESH_Mesh_var mesh = aGrp->GetMesh();
1786     if ( mesh->_is_nil() || mesh->GetId() != this->GetId() )
1787       continue;
1788
1789     SMDS_ElemIteratorPtr elIt = GetElements( aGrp, SMESH::ALL );
1790     if ( !elIt ) continue;
1791
1792     if ( theElemType == SMESH::NODE ) // get all nodes of elements
1793     {
1794       while ( elIt->more() ) {
1795         const SMDS_MeshElement* el = elIt->next();
1796         SMDS_ElemIteratorPtr nIt = el->nodesIterator();
1797         while ( nIt->more() )
1798           resGroupCore.Add( nIt->next() );
1799       }
1800     }
1801     // get elements of theElemType based on nodes of every element of group
1802     else if ( theUnderlyingOnly )
1803     {
1804       while ( elIt->more() )
1805       {
1806         const SMDS_MeshElement* el = elIt->next(); // an element of ref group
1807         TIDSortedElemSet elNodes( el->begin_nodes(), el->end_nodes() );
1808         TIDSortedElemSet checkedElems;
1809         SMDS_NodeIteratorPtr nIt = el->nodeIterator();
1810         while ( nIt->more() )
1811         {
1812           const SMDS_MeshNode* n = nIt->next();
1813           SMDS_ElemIteratorPtr elOfTypeIt = n->GetInverseElementIterator( anElemType );
1814           // check nodes of elements of theElemType around el
1815           while ( elOfTypeIt->more() )
1816           {
1817             const SMDS_MeshElement* elOfType = elOfTypeIt->next();
1818             if ( !checkedElems.insert( elOfType ).second ) continue;
1819             nbNodes   = elOfType->NbNodes();
1820             nbCorners = elOfType->NbCornerNodes();
1821             nbCommon  = 0;
1822             bool toStopChecking = false;
1823             SMDS_ElemIteratorPtr nIt2 = elOfType->nodesIterator();
1824             for ( nbChecked = 1; nIt2->more() && !toStopChecking; ++nbChecked )
1825               if ( elNodes.count( nIt2->next() ) &&
1826                    isToInclude( nbChecked, ++nbCommon, nbNodes, nbCorners, toStopChecking ))
1827               {
1828                 resGroupCore.Add( elOfType );
1829                 break;
1830               }
1831           }
1832         }
1833       }
1834     }
1835     // get all nodes of elements of groups
1836     else
1837     {
1838       while ( elIt->more() )
1839       {
1840         const SMDS_MeshElement* el = elIt->next(); // an element of group
1841         SMDS_NodeIteratorPtr nIt = el->nodeIterator();
1842         while ( nIt->more() )
1843         {
1844           const SMDS_MeshNode* n = nIt->next();
1845           if ( n->GetID() >= (int) isNodeInGroups.size() )
1846             isNodeInGroups.resize( n->GetID() + 1, false );
1847           isNodeInGroups[ n->GetID() ] = true;
1848         }
1849       }
1850     }
1851   }
1852
1853   // Get elements of theElemType based on a certain number of nodes of elements of groups
1854   if ( !theUnderlyingOnly && !isNodeInGroups.empty() )
1855   {
1856     const SMDS_MeshNode* n;
1857     vector<bool> isElemChecked( aMeshDS->MaxElementID() + 1 );
1858     const int isNodeInGroupsSize = isNodeInGroups.size();
1859     for ( int iN = 0; iN < isNodeInGroupsSize; ++iN )
1860     {
1861       if ( !isNodeInGroups[ iN ] ||
1862            !( n = aMeshDS->FindNode( iN )))
1863         continue;
1864
1865       // check nodes of elements of theElemType around n
1866       SMDS_ElemIteratorPtr elOfTypeIt = n->GetInverseElementIterator( anElemType );
1867       while ( elOfTypeIt->more() )
1868       {
1869         const SMDS_MeshElement*  elOfType = elOfTypeIt->next();
1870         vector<bool>::reference isChecked = isElemChecked[ elOfType->GetID() ];
1871         if ( isChecked )
1872           continue;
1873         isChecked = true;
1874
1875         nbNodes   = elOfType->NbNodes();
1876         nbCorners = elOfType->NbCornerNodes();
1877         nbCommon  = 0;
1878         bool toStopChecking = false;
1879         SMDS_ElemIteratorPtr nIt = elOfType->nodesIterator();
1880         for ( nbChecked = 1; nIt->more() && !toStopChecking; ++nbChecked )
1881         {
1882           const int nID = nIt->next()->GetID();
1883           if ( nID < isNodeInGroupsSize && isNodeInGroups[ nID ] &&
1884                isToInclude( nbChecked, ++nbCommon, nbNodes, nbCorners, toStopChecking ))
1885           {
1886             resGroupCore.Add( elOfType );
1887             break;
1888           }
1889         }
1890       }
1891     }
1892   }
1893
1894   // Update Python script
1895   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var( _this())
1896          << ".CreateDimGroup( "
1897          << theGroups << ", " << theElemType << ", '" << theName << "', "
1898          << nbCoNoStr << ", " << theUnderlyingOnly << ")";
1899
1900   SMESH_CATCH( SMESH::throwCorbaException );
1901
1902   return aResGrp._retn();
1903 }
1904
1905 //================================================================================
1906 /*!
1907  * \brief Distribute all faces of the mesh between groups using sharp edges and optionally
1908  *        existing 1D elements as group boundaries.
1909  *  \param [in] theSharpAngle - edge is considered sharp if an angle between normals of
1910  *              adjacent faces is more than \a sharpAngle in degrees.
1911  *  \param [in] theCreateEdges - to create 1D elements for detected sharp edges.
1912  *  \param [in] theUseExistingEdges - to use existing edges as group boundaries
1913  *  \return ListOfGroups - the created groups
1914  */
1915 //================================================================================
1916
1917 SMESH::ListOfGroups*
1918 SMESH_Mesh_i::FaceGroupsSeparatedByEdges( CORBA::Double  theSharpAngle,
1919                                           CORBA::Boolean theCreateEdges,
1920                                           CORBA::Boolean theUseExistingEdges )
1921   throw (SALOME::SALOME_Exception)
1922 {
1923   if ( theSharpAngle < 0 || theSharpAngle > 180 )
1924     THROW_SALOME_CORBA_EXCEPTION("Invalid sharp angle, it must be between 0 and 180 degrees",
1925                                  SALOME::BAD_PARAM);
1926
1927   SMESH::ListOfGroups_var resultGroups = new SMESH::ListOfGroups;
1928
1929   TPythonDump pyDump;
1930
1931   SMESH_TRY;
1932   if ( _preMeshInfo )
1933     _preMeshInfo->FullLoadFromFile();
1934
1935   SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
1936
1937   std::vector< SMESH_MeshAlgos::Edge > edges =
1938     SMESH_MeshAlgos::FindSharpEdges( meshDS, theSharpAngle, theUseExistingEdges );
1939
1940   if ( theCreateEdges )
1941   {
1942     std::vector<const SMDS_MeshNode *> nodes(2);
1943     for ( size_t i = 0; i < edges.size(); ++i )
1944     {
1945       nodes[0] = edges[i]._node1;
1946       nodes[1] = edges[i]._node2;
1947       if ( meshDS->FindElement( nodes, SMDSAbs_Edge ))
1948         continue;
1949       if ( edges[i]._medium )
1950         meshDS->AddEdge( edges[i]._node1, edges[i]._node2, edges[i]._medium );
1951       else
1952         meshDS->AddEdge( edges[i]._node1, edges[i]._node2 );
1953     }
1954   }
1955
1956   std::vector< std::vector< const SMDS_MeshElement* > > faceGroups =
1957     SMESH_MeshAlgos::SeparateFacesByEdges( meshDS, edges );
1958
1959   SMESH::SMESH_MeshEditor_var editor = GetMeshEditor(); // create _editor
1960
1961   resultGroups->length( faceGroups.size() );
1962   for ( size_t iG = 0; iG < faceGroups.size(); ++iG )
1963   {
1964     SMESH::SMESH_Group_var group = CreateGroup( SMESH::FACE,
1965                                                 _editor->GenerateGroupName("Group").c_str());
1966     resultGroups[iG] = SMESH::SMESH_Group::_duplicate( group );
1967
1968     SMESHDS_GroupBase* groupBaseDS =
1969       SMESH::DownCast<SMESH_GroupBase_i*>( group )->GetGroupDS();
1970     SMDS_MeshGroup& groupCore = static_cast< SMESHDS_Group* >( groupBaseDS )->SMDSGroup();
1971
1972     std::vector< const SMDS_MeshElement* >& faces = faceGroups[ iG ];
1973     for ( size_t i = 0; i < faces.size(); ++i )
1974       groupCore.Add( faces[i] );
1975   }
1976
1977   pyDump << resultGroups << " = " << SMESH::SMESH_Mesh_var(_this())
1978          << ".FaceGroupsSeparatedByEdges( "
1979          << TVar( theSharpAngle ) << ", "
1980          << theCreateEdges << ", "
1981          << theUseExistingEdges << " )";
1982
1983   SMESH_CATCH( SMESH::throwCorbaException );
1984   return resultGroups._retn();
1985
1986 }
1987
1988 //================================================================================
1989 /*!
1990  * \brief Remember GEOM group data
1991  */
1992 //================================================================================
1993
1994 void SMESH_Mesh_i::addGeomGroupData(GEOM::GEOM_Object_ptr theGeomObj,
1995                                     CORBA::Object_ptr     theSmeshObj)
1996 {
1997   if ( CORBA::is_nil( theGeomObj ) || theGeomObj->GetType() != GEOM_GROUP )
1998     return;
1999   // group SO
2000   SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( theGeomObj );
2001   if ( groupSO->_is_nil() )
2002     return;
2003   // group indices
2004   GEOM::GEOM_Gen_var               geomGen = _gen_i->GetGeomEngine( theGeomObj );
2005   GEOM::GEOM_IGroupOperations_wrap groupOp = geomGen->GetIGroupOperations();
2006   GEOM::ListOfLong_var                 ids = groupOp->GetObjects( theGeomObj );
2007
2008   // store data
2009   _geomGroupData.push_back( TGeomGroupData() );
2010   TGeomGroupData & groupData = _geomGroupData.back();
2011   // entry
2012   CORBA::String_var entry = groupSO->GetID();
2013   groupData._groupEntry = entry.in();
2014   // indices
2015   for ( CORBA::ULong i = 0; i < ids->length(); ++i )
2016     groupData._indices.insert( ids[i] );
2017   // SMESH object
2018   groupData._smeshObject = CORBA::Object::_duplicate( theSmeshObj );
2019   // shape index in SMESHDS
2020   // TopoDS_Shape shape = _gen_i->GeomObjectToShape( theGeomObj );
2021   // groupData._dsID = shape.IsNull() ? 0 : _impl->GetSubMesh( shape )->GetId();
2022 }
2023
2024 //================================================================================
2025 /*!
2026  * Remove GEOM group data relating to removed smesh object
2027  */
2028 //================================================================================
2029
2030 void SMESH_Mesh_i::removeGeomGroupData(CORBA::Object_ptr theSmeshObj)
2031 {
2032   list<TGeomGroupData>::iterator
2033     data = _geomGroupData.begin(), dataEnd = _geomGroupData.end();
2034   for ( ; data != dataEnd; ++data ) {
2035     if ( theSmeshObj->_is_equivalent( data->_smeshObject )) {
2036       _geomGroupData.erase( data );
2037       return;
2038     }
2039   }
2040 }
2041
2042 //================================================================================
2043 /*!
2044 * \brief Replace a shape in the mesh upon Break Link
2045 */
2046 //================================================================================
2047
2048 void SMESH_Mesh_i::ReplaceShape(GEOM::GEOM_Object_ptr theNewGeom)
2049   throw (SALOME::SALOME_Exception)
2050 {
2051   // check if geometry changed
2052   bool geomChanged = true;
2053   GEOM::GEOM_Object_var oldGeom = GetShapeToMesh();
2054   if ( !theNewGeom->_is_nil() && !oldGeom->_is_nil() )
2055     geomChanged = ( //oldGeom->_is_equivalent( theNewGeom ) ||
2056                    oldGeom->GetTick() < theNewGeom->GetTick() );
2057
2058   TopoDS_Shape S = _impl->GetShapeToMesh();
2059   GEOM_Client* geomClient = _gen_i->GetShapeReader();
2060   TCollection_AsciiString aIOR;
2061   CORBA::String_var ior;
2062   if ( geomClient->Find( S, aIOR ))
2063     geomClient->RemoveShapeFromBuffer( aIOR );
2064
2065   // clear buffer also for sub-groups
2066   const std::set<SMESHDS_GroupBase*>& groups = _impl->GetMeshDS()->GetGroups();
2067   std::set<SMESHDS_GroupBase*>::const_iterator g = groups.begin();
2068   for (; g != groups.end(); ++g)
2069     if (const SMESHDS_GroupOnGeom* group = dynamic_cast<SMESHDS_GroupOnGeom*>(*g))
2070     {
2071       const TopoDS_Shape& s = group->GetShape();
2072       if ( geomClient->Find( s, aIOR ))
2073         geomClient->RemoveShapeFromBuffer( aIOR );
2074     }
2075
2076   typedef struct {
2077     int shapeID, fromID, toID; // indices of elements of a sub-mesh
2078   } TRange;
2079   std::vector< TRange > elemRanges, nodeRanges; // elements of sub-meshes
2080   std::vector< SMDS_PositionPtr > positions; // node positions
2081   SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
2082   if ( !geomChanged )
2083   {
2084     // store positions of elements on geometry
2085     Load();
2086     if ( meshDS->MaxNodeID()    > meshDS->NbNodes() ||
2087          meshDS->MaxElementID() > meshDS->NbElements() )
2088     {
2089       meshDS->Modified();
2090       meshDS->CompactMesh();
2091     }
2092     positions.resize( meshDS->NbNodes() + 1 );
2093     for ( SMDS_NodeIteratorPtr nodeIt = meshDS->nodesIterator(); nodeIt->more(); )
2094     {
2095       const SMDS_MeshNode* n = nodeIt->next();
2096       positions[ n->GetID() ] = n->GetPosition();
2097     }
2098
2099     // remove elements from sub-meshes to avoid their removal at hypotheses addition
2100     for ( int isNode = 0; isNode < 2; ++isNode )
2101     {
2102       std::vector< TRange > & ranges = isNode ? nodeRanges : elemRanges;
2103       ranges.reserve( meshDS->MaxShapeIndex() + 10 );
2104       ranges.push_back( TRange{ 0,0,0 });
2105       SMDS_ElemIteratorPtr elemIt = meshDS->elementsIterator( isNode ? SMDSAbs_Node : SMDSAbs_All );
2106       while ( elemIt->more() )
2107       {
2108         const SMDS_MeshElement* e = elemIt->next();
2109         const int          elemID = e->GetID();
2110         const int         shapeID = e->GetShapeID();
2111         TRange &        lastRange = ranges.back();
2112         if ( lastRange.shapeID != shapeID ||
2113              lastRange.toID    != elemID )
2114           ranges.push_back( TRange{ shapeID, elemID, elemID + 1 });
2115         else
2116           lastRange.toID = elemID + 1;
2117
2118         if ( SMESHDS_SubMesh* sm = meshDS->MeshElements( shapeID ))
2119         {
2120           if ( isNode ) sm->RemoveNode( static_cast< const SMDS_MeshNode *>( e ));
2121           else          sm->RemoveElement( e );
2122         }
2123       }
2124     }
2125   }
2126
2127
2128   // update the reference to theNewGeom (needed for correct execution of a dumped python script)
2129   SMESH::SMESH_Mesh_var   me = _this();
2130   SALOMEDS::SObject_wrap aSO = _gen_i->ObjectToSObject( me );
2131   CORBA::String_var    entry = theNewGeom->GetStudyEntry();
2132   if ( !aSO->_is_nil() )
2133   {
2134     SALOMEDS::SObject_wrap aShapeRefSO;
2135     if ( aSO->FindSubObject( _gen_i->GetRefOnShapeTag(), aShapeRefSO.inout() ))
2136     {
2137       SALOMEDS::SObject_wrap    aShapeSO = _gen_i->getStudyServant()->FindObjectID( entry );
2138       SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
2139       builder->Addreference( aShapeRefSO, aShapeSO );
2140     }
2141   }
2142
2143   // re-assign global hypotheses to the new shape
2144   _mainShapeTick = geomChanged ? -1 : theNewGeom->GetTick();
2145   CheckGeomModif( true );
2146
2147   if ( !geomChanged )
2148   {
2149     // restore positions of elements on geometry
2150     for ( int isNode = 0; isNode < 2; ++isNode )
2151     {
2152       std::vector< TRange > & ranges = isNode ? nodeRanges : elemRanges;
2153       for ( size_t i = 1; i < ranges.size(); ++i )
2154       {
2155         int elemID = ranges[ i ].fromID;
2156         int   toID = ranges[ i ].toID;
2157         SMESHDS_SubMesh * smDS = meshDS->NewSubMesh( ranges[ i ].shapeID );
2158         if ( isNode )
2159           for ( ; elemID < toID; ++elemID )
2160             smDS->AddNode( meshDS->FindNode( elemID ));
2161         else
2162           for ( ; elemID < toID; ++elemID )
2163             smDS->AddElement( meshDS->FindElement( elemID ));
2164
2165         if ( SMESH_subMesh* sm = _impl->GetSubMeshContaining( ranges[ i ].shapeID ))
2166           sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
2167       }
2168     }
2169     for ( unsigned int nodeID = 1; nodeID < positions.size(); ++nodeID )
2170       if ( positions[ nodeID ])
2171         if ( SMDS_MeshNode* n = const_cast< SMDS_MeshNode*>( meshDS->FindNode( nodeID )))
2172           n->SetPosition( positions[ nodeID ], n->GetShapeID() );
2173
2174     // restore icons
2175     _gen_i->UpdateIcons( SMESH::SMESH_Mesh_var( _this() ));
2176   }
2177
2178   TPythonDump() << "SHAPERSTUDY.breakLinkForSubElements(salome.ObjectToSObject("
2179                 << me <<".GetMesh()), " << entry.in() << ")";
2180
2181   TPythonDump() <<  me << ".ReplaceShape( " << entry.in() << " )";
2182
2183 }
2184
2185 //================================================================================
2186 /*!
2187  * \brief Return new group contents if it has been changed and update group data
2188  */
2189 //================================================================================
2190
2191 enum { ONLY_IF_CHANGED, IS_BREAK_LINK, MAIN_TRANSFORMED };
2192
2193 TopoDS_Shape SMESH_Mesh_i::newGroupShape( TGeomGroupData & groupData, int how )
2194 {
2195   TopoDS_Shape newShape;
2196   SALOMEDS::SObject_wrap groupSO;
2197
2198   if ( how == IS_BREAK_LINK )
2199   {
2200     SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( groupData._smeshObject );
2201     SALOMEDS::SObject_wrap geomRefSO;
2202     if ( !meshSO->_is_nil() &&
2203          meshSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ))
2204     {
2205       geomRefSO->ReferencedObject( groupSO.inout() );
2206     }
2207   }
2208   else
2209   {
2210     // get geom group
2211     groupSO = _gen_i->getStudyServant()->FindObjectID( groupData._groupEntry.c_str() );
2212   }
2213
2214   if ( groupSO->_is_nil() )
2215     return newShape;
2216
2217   CORBA::Object_var      groupObj = _gen_i->SObjectToObject( groupSO );
2218   GEOM::GEOM_Object_var geomGroup = GEOM::GEOM_Object::_narrow( groupObj );
2219   if ( geomGroup->_is_nil() )
2220     return newShape;
2221
2222   // get indices of group items
2223   set<int> curIndices;
2224   GEOM::GEOM_Gen_var               geomGen = _gen_i->GetGeomEngine( geomGroup );
2225   GEOM::GEOM_IGroupOperations_wrap groupOp = geomGen->GetIGroupOperations();
2226   GEOM::ListOfLong_var                 ids = groupOp->GetObjects( geomGroup );
2227   for ( CORBA::ULong i = 0; i < ids->length(); ++i )
2228     curIndices.insert( ids[i] );
2229
2230   bool sameIndices = ( groupData._indices == curIndices );
2231   if ( how == ONLY_IF_CHANGED && sameIndices )
2232     return newShape; // group not changed
2233
2234   // update data
2235   CORBA::String_var entry = geomGroup->GetStudyEntry();
2236   groupData._groupEntry = entry.in();
2237   groupData._indices = curIndices;
2238
2239   newShape = _gen_i->GeomObjectToShape( geomGroup );
2240
2241   // check if newShape is up-to-date
2242   if ( !newShape.IsNull() && ids->length() > 0 )
2243   {
2244     bool toUpdate = ! _impl->GetMeshDS()->IsGroupOfSubShapes( newShape );
2245     if ( !toUpdate )
2246     {
2247       TopExp_Explorer exp( newShape, (TopAbs_ShapeEnum)( groupOp->GetType( geomGroup )));
2248       for ( ; exp.More() && !toUpdate; exp.Next() )
2249       {
2250         int ind = _impl->GetMeshDS()->ShapeToIndex( exp.Current() );
2251         toUpdate = ( curIndices.erase( ind ) == 0 );
2252       }
2253       if ( !curIndices.empty() )
2254         toUpdate = true;
2255     }
2256     if ( toUpdate )
2257     {
2258       GEOM_Client*    geomClient = _gen_i->GetShapeReader();
2259       CORBA::String_var groupIOR = geomGen->GetStringFromIOR( geomGroup );
2260       geomClient->RemoveShapeFromBuffer( groupIOR.in() );
2261       newShape = _gen_i->GeomObjectToShape( geomGroup );
2262     }
2263   }
2264   else
2265   {
2266     // geom group becomes empty - return empty compound
2267     TopoDS_Compound compound;
2268     BRep_Builder().MakeCompound(compound);
2269     newShape = compound;
2270   }
2271
2272   return newShape;
2273 }
2274
2275 namespace
2276 {
2277   //-----------------------------------------------------------------------------
2278   /*!
2279    * \brief Storage of shape and index used in CheckGeomGroupModif()
2280    */
2281   struct TIndexedShape
2282   {
2283     int          _index;
2284     TopoDS_Shape _shape;
2285     TIndexedShape( int i, const TopoDS_Shape& s ):_index(i), _shape(s) {}
2286   };
2287   //-----------------------------------------------------------------------------
2288   /*!
2289    * \brief Data to re-create a group on geometry
2290    */
2291   struct TGroupOnGeomData
2292   {
2293     int                 _oldID;
2294     TopoDS_Shape        _shape;
2295     SMDSAbs_ElementType _type;
2296     std::string         _name;
2297     Quantity_Color      _color;
2298
2299     TGroupOnGeomData( const SMESHDS_GroupOnGeom* group )
2300     {
2301       _oldID = group->GetID();
2302       _type  = group->GetType();
2303       _name  = group->GetStoreName();
2304       _color = group->GetColor();
2305     }
2306   };
2307
2308   //-----------------------------------------------------------------------------
2309   /*!
2310    * \brief Check if a filter is still valid after geometry removal
2311    */
2312   bool isValidGeomFilter( SMESH::Filter_var theFilter )
2313   {
2314     if ( theFilter->_is_nil() )
2315       return false;
2316     SMESH::Filter::Criteria_var criteria;
2317     theFilter->GetCriteria( criteria.out() );
2318
2319     for ( CORBA::ULong iCr = 0; iCr < criteria->length(); ++iCr )
2320     {
2321       const char* thresholdID = criteria[ iCr ].ThresholdID.in();
2322       std::string entry;
2323       switch ( criteria[ iCr ].Type )
2324       {
2325       case SMESH::FT_BelongToGeom:
2326       case SMESH::FT_BelongToPlane:
2327       case SMESH::FT_BelongToCylinder:
2328       case SMESH::FT_BelongToGenSurface:
2329       case SMESH::FT_LyingOnGeom:
2330         entry = thresholdID;
2331         break;
2332       case SMESH::FT_ConnectedElements:
2333         if ( thresholdID )
2334         {
2335           entry = thresholdID;
2336           break;
2337         }
2338       default:
2339         continue;
2340       }
2341       SMESH_Gen_i*           gen = SMESH_Gen_i::GetSMESHGen();
2342       SALOMEDS::SObject_wrap  so = gen->getStudyServant()->FindObjectID( entry.c_str() );
2343       if ( so->_is_nil() )
2344         return false;
2345       CORBA::Object_var      obj = so->GetObject();
2346       GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( obj );
2347       if ( gen->GeomObjectToShape( geom ).IsNull() )
2348         return false;
2349
2350     } // loop on criteria
2351
2352     return true;
2353   }
2354 }
2355
2356 //=============================================================================
2357 /*!
2358  * \brief Update data if geometry changes
2359  *
2360  * Issue 0022501
2361  */
2362 //=============================================================================
2363
2364 void SMESH_Mesh_i::CheckGeomModif( bool theIsBreakLink )
2365 {
2366   SMESH::SMESH_Mesh_var me = _this();
2367   GEOM::GEOM_Object_var mainGO = GetShapeToMesh();
2368
2369   TPythonDump dumpNothing; // prevent any dump
2370
2371   //bool removedFromClient = false;
2372
2373   if ( mainGO->_is_nil() ) // GEOM_Client cleared or geometry removed? (IPAL52735, PAL23636)
2374   {
2375     //removedFromClient = _impl->HasShapeToMesh();
2376
2377     // try to find geometry by study reference
2378     SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( me );
2379     SALOMEDS::SObject_wrap geomRefSO, geomSO;
2380     if ( !meshSO->_is_nil() &&
2381          meshSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
2382          geomRefSO->ReferencedObject( geomSO.inout() ))
2383     {
2384       CORBA::Object_var geomObj = _gen_i->SObjectToObject( geomSO );
2385       mainGO = GEOM::GEOM_Object::_narrow( geomObj );
2386     }
2387
2388     if ( mainGO->_is_nil() &&    // geometry removed ==>
2389          !geomRefSO->_is_nil() ) // remove geom dependent data: sub-meshes etc.
2390     {
2391       // convert geom dependent groups into standalone ones
2392       CheckGeomGroupModif();
2393
2394       _impl->ShapeToMesh( TopoDS_Shape() );
2395
2396       // remove sub-meshes
2397       std::map<int, SMESH::SMESH_subMesh_ptr>::iterator i_sm = _mapSubMeshIor.begin();
2398       while ( i_sm != _mapSubMeshIor.end() )
2399       {
2400         SMESH::SMESH_subMesh_ptr sm = i_sm->second;
2401         ++i_sm;
2402         RemoveSubMesh( sm );
2403       }
2404       // remove all children except groups in the study
2405       SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
2406       SALOMEDS::SObject_wrap so;
2407       for ( CORBA::Long tag = SMESH::Tag_RefOnShape; tag <= SMESH::Tag_LastSubMesh; ++tag )
2408         if ( meshSO->FindSubObject( tag, so.inout() ))
2409           builder->RemoveObjectWithChildren( so );
2410
2411       _gen_i->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED" );
2412
2413       return;
2414     }
2415   }
2416
2417   if ( !_impl->HasShapeToMesh() ) return;
2418
2419
2420   // Update after group modification
2421
2422   const bool geomChanged = ( mainGO->GetTick() != _mainShapeTick );
2423   if ( !theIsBreakLink )
2424     if ( mainGO->GetType() == GEOM_GROUP || !geomChanged )  // is group or not modified
2425     {
2426       int nb = NbNodes() + NbElements();
2427       CheckGeomGroupModif();
2428       if ( nb != NbNodes() + NbElements() ) // something removed due to hypotheses change
2429         _gen_i->UpdateIcons( me );
2430       return;
2431     }
2432
2433   // Update after shape modification or breakLink w/o geometry change
2434
2435   GEOM_Client* geomClient = _gen_i->GetShapeReader();
2436   if ( !geomClient ) return;
2437   GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine( mainGO );
2438   if ( geomGen->_is_nil() ) return;
2439   CORBA::String_var geomComponentType = geomGen->ComponentDataType();
2440   bool isShaper = ( strcmp( geomComponentType.in(), "SHAPERSTUDY" ) == 0 );
2441
2442   SMESHDS_Mesh * meshDS = _impl->GetMeshDS();
2443
2444   TopoDS_Shape newShape = _gen_i->GeomObjectToShape( mainGO );
2445   if ( meshDS->ShapeToIndex( newShape ) == 1 ) // not yet updated
2446   {
2447     CORBA::String_var ior = geomGen->GetStringFromIOR( mainGO );
2448     geomClient->RemoveShapeFromBuffer( ior.in() );
2449     newShape = _gen_i->GeomObjectToShape( mainGO );
2450   }
2451
2452   // Update data taking into account that if topology doesn't change
2453   // all sub-shapes change but IDs of sub-shapes remain (except for geom groups)
2454
2455   if ( _preMeshInfo )
2456     _preMeshInfo->ForgetAllData();
2457
2458   if ( geomChanged || !isShaper )
2459     _impl->Clear();
2460   if ( newShape.IsNull() )
2461     return;
2462
2463   _mainShapeTick = mainGO->GetTick();
2464
2465   // store data of groups on geometry including new TopoDS_Shape's
2466   std::vector< TGroupOnGeomData > groupsData;
2467   const std::set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
2468   groupsData.reserve( groups.size() );
2469   TopTools_DataMapOfShapeShape old2newShapeMap;
2470   std::set<SMESHDS_GroupBase*>::const_iterator g = groups.begin();
2471   for ( ; g != groups.end(); ++g )
2472   {
2473     if ( const SMESHDS_GroupOnGeom* group = dynamic_cast< SMESHDS_GroupOnGeom* >( *g ))
2474     {
2475       groupsData.push_back( TGroupOnGeomData( group ));
2476
2477       // get a new shape
2478       SMESH::SMESH_GroupOnGeom_var gog;
2479       std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.find( group->GetID() );
2480       if ( i_grp != _mapGroups.end() )
2481         gog = SMESH::SMESH_GroupOnGeom::_narrow( i_grp->second );
2482
2483       GEOM::GEOM_Object_var geom;
2484       if ( !gog->_is_nil() )
2485       {
2486         if ( !theIsBreakLink )
2487           geom = gog->GetShape();
2488
2489         if ( theIsBreakLink || geom->_is_nil() )
2490         {
2491           SALOMEDS::SObject_wrap grpSO = _gen_i->ObjectToSObject( gog );
2492           SALOMEDS::SObject_wrap geomRefSO, geomSO;
2493           if ( !grpSO->_is_nil() &&
2494                grpSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
2495                geomRefSO->ReferencedObject( geomSO.inout() ))
2496           {
2497             CORBA::Object_var geomObj = _gen_i->SObjectToObject( geomSO );
2498             geom = GEOM::GEOM_Object::_narrow( geomObj );
2499           }
2500         }
2501       }
2502       if ( old2newShapeMap.IsBound( group->GetShape() ))
2503       {
2504         groupsData.back()._shape = old2newShapeMap( group->GetShape() );
2505       }
2506       else if ( !geom->_is_nil() )
2507       {
2508         groupsData.back()._shape = _gen_i->GeomObjectToShape( geom );
2509         if ( meshDS->IsGroupOfSubShapes( groupsData.back()._shape ))
2510         {
2511           CORBA::String_var ior = geomGen->GetStringFromIOR( geom );
2512           geomClient->RemoveShapeFromBuffer( ior.in() );
2513           groupsData.back()._shape = _gen_i->GeomObjectToShape( geom );
2514         }
2515         old2newShapeMap.Bind( group->GetShape(), groupsData.back()._shape );
2516       }
2517       
2518     }
2519   }
2520   // store assigned hypotheses
2521   std::vector< pair< int, THypList > > ids2Hyps;
2522   const ShapeToHypothesis & hyps = meshDS->GetHypotheses();
2523   for ( ShapeToHypothesis::Iterator s2hyps( hyps ); s2hyps.More(); s2hyps.Next() )
2524   {
2525     const TopoDS_Shape& s = s2hyps.Key();
2526     const THypList&  hyps = s2hyps.ChangeValue();
2527     ids2Hyps.push_back( make_pair( meshDS->ShapeToIndex( s ), hyps ));
2528   }
2529
2530   std::multimap< std::set<int>, int > ii2iMap; // group sub-ids to group id in SMESHDS
2531
2532   // count shapes excluding compounds corresponding to geom groups
2533   int oldNbSubShapes = meshDS->MaxShapeIndex();
2534   for ( ; oldNbSubShapes > 0; --oldNbSubShapes )
2535   {
2536     const TopoDS_Shape& s = meshDS->IndexToShape( oldNbSubShapes );
2537     if ( s.IsNull() || s.ShapeType() != TopAbs_COMPOUND )
2538       break;
2539     // fill ii2iMap
2540     std::set<int> subIds;
2541     for ( TopoDS_Iterator it( s ); it.More(); it.Next() )
2542       subIds.insert( meshDS->ShapeToIndex( it.Value() ));
2543     ii2iMap.insert( std::make_pair( subIds, oldNbSubShapes ));
2544   }
2545
2546   // check if shape topology changes - save shape type per shape ID
2547   std::vector< TopAbs_ShapeEnum > shapeTypes( Max( oldNbSubShapes + 1, 1 ));
2548   for ( int shapeID = oldNbSubShapes; shapeID > 0; --shapeID )
2549     shapeTypes[ shapeID ] = meshDS->IndexToShape( shapeID ).ShapeType();
2550
2551   // change shape to mesh
2552   _impl->ShapeToMesh( TopoDS_Shape() );
2553   _impl->ShapeToMesh( newShape );
2554
2555   // check if shape topology changes - check new shape types
2556   bool sameTopology = ( oldNbSubShapes == meshDS->MaxShapeIndex() );
2557   for ( int shapeID = oldNbSubShapes; shapeID > 0 &&  sameTopology; --shapeID )
2558   {
2559     const TopoDS_Shape& s = meshDS->IndexToShape( shapeID );
2560     sameTopology = ( !s.IsNull() && s.ShapeType() == shapeTypes[ shapeID ]);
2561   }
2562
2563   // re-add shapes (compounds) of geom groups
2564   typedef std::map< std::vector< int >, TGeomGroupData* > TIndices2GroupData;
2565   TIndices2GroupData ii2grData;
2566   std::vector< int > ii;
2567   std::map< int, int > old2newIDs; // group IDs
2568   std::list<TGeomGroupData>::iterator dataIt = _geomGroupData.begin();
2569   for ( ; dataIt != _geomGroupData.end(); ++dataIt )
2570   {
2571     TGeomGroupData* data = &(*dataIt);
2572     ii.reserve( data->_indices.size() );
2573     ii.assign( data->_indices.begin(), data->_indices.end() );
2574     TIndices2GroupData::iterator ii2gd = ii2grData.insert( std::make_pair( ii, data )).first;
2575     if ( ii2gd->second != data )
2576     {
2577       data->_groupEntry = ii2gd->second->_groupEntry;
2578       data->_indices    = ii2gd->second->_indices;
2579       continue;
2580     }
2581     const int  oldNbSub = data->_indices.size();
2582     const int soleOldID = oldNbSub == 1 ? *data->_indices.begin() : 0;
2583     int oldID = 0;
2584     std::multimap< std::set<int>, int >::iterator ii2i = ii2iMap.find( data->_indices );
2585     if ( ii2i != ii2iMap.end() )
2586     {
2587       oldID = ii2i->second;
2588       ii2iMap.erase( ii2i );
2589     }
2590     if ( !oldID && oldNbSub == 1 )
2591       oldID = soleOldID;
2592     if ( old2newIDs.count( oldID ))
2593       continue;
2594
2595     int how = ( theIsBreakLink || !sameTopology ) ? IS_BREAK_LINK : MAIN_TRANSFORMED;
2596     newShape = newGroupShape( *data, how );
2597
2598     if ( !newShape.IsNull() )
2599     {
2600       if ( oldNbSub > 1 && meshDS->ShapeToIndex( newShape ) > 0 ) // group reduced to one sub-shape
2601       {
2602         TopoDS_Compound compound;
2603         BRep_Builder().MakeCompound( compound );
2604         BRep_Builder().Add( compound, newShape );
2605         newShape = compound;
2606       }
2607       int newID = _impl->GetSubMesh( newShape )->GetId();
2608       if ( oldID /*&& oldID != newID*/ )
2609         old2newIDs.insert( std::make_pair( oldID, newID ));
2610       if ( oldNbSub == 1 )
2611         old2newIDs.insert( std::make_pair( soleOldID, newID ));
2612     }
2613   }
2614
2615   // re-assign hypotheses
2616   for ( size_t i = 0; i < ids2Hyps.size(); ++i )
2617   {
2618     int sID = ids2Hyps[i].first;
2619     if ( sID != 1 )
2620     {
2621       std::map< int, int >::iterator o2n = old2newIDs.find( sID );
2622       if ( o2n != old2newIDs.end() )
2623         sID = o2n->second;
2624       else if ( !sameTopology )
2625         continue;
2626     }
2627     const TopoDS_Shape& s = meshDS->IndexToShape( sID );
2628     if ( s.IsNull() )
2629       continue;
2630     const THypList& hyps = ids2Hyps[i].second;
2631     THypList::const_iterator h = hyps.begin();
2632     for ( ; h != hyps.end(); ++h )
2633       _impl->AddHypothesis( s, (*h)->GetID() );
2634   }
2635
2636   {
2637     // restore groups on geometry
2638     for ( size_t i = 0; i < groupsData.size(); ++i )
2639     {
2640       const TGroupOnGeomData& data = groupsData[i];
2641       if ( data._shape.IsNull() )
2642         continue;
2643
2644       std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i2g = _mapGroups.find( data._oldID );
2645       if ( i2g == _mapGroups.end() ) continue;
2646
2647       SMESH_GroupBase_i* gr_i = SMESH::DownCast<SMESH_GroupBase_i*>( i2g->second );
2648       if ( !gr_i ) continue;
2649
2650       SMESH_Group* g = _impl->AddGroup( data._type, data._name.c_str(), data._oldID, data._shape );
2651       if ( !g )
2652         _mapGroups.erase( i2g );
2653       else
2654         g->GetGroupDS()->SetColor( data._color );
2655     }
2656
2657     if ( !sameTopology )
2658     {
2659       std::map< int, int >::iterator o2n = old2newIDs.begin();
2660       for ( ; o2n != old2newIDs.end(); ++o2n )
2661       {
2662         int newID = o2n->second, oldID = o2n->first;
2663         if ( newID == oldID || !_mapSubMesh.count( oldID ))
2664           continue;
2665         if ( newID > 0 )
2666         {
2667           _mapSubMesh   [ newID ] = _impl->GetSubMeshContaining( newID );
2668           _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2669           _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2670         }
2671         _mapSubMesh.   erase(oldID);
2672         _mapSubMesh_i. erase(oldID);
2673         _mapSubMeshIor.erase(oldID);
2674         if ( newID > 0 )
2675           _mapSubMesh_i [ newID ]->changeLocalId( newID );
2676       }
2677     }
2678
2679     // update _mapSubMesh
2680     std::map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
2681     for ( ; i_sm != _mapSubMesh.end(); ++i_sm )
2682       i_sm->second = _impl->GetSubMesh( meshDS->IndexToShape( i_sm->first ));
2683   }
2684
2685   if ( !sameTopology )
2686   {
2687     // remove invalid study sub-objects
2688     CheckGeomGroupModif();
2689   }
2690
2691   _gen_i->UpdateIcons( me );
2692
2693   if ( !theIsBreakLink && isShaper )
2694   {
2695     SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( me );
2696     if ( !meshSO->_is_nil() )
2697       _gen_i->SetPixMap(meshSO, "ICON_SMESH_TREE_GEOM_MODIF");
2698   }
2699 }
2700
2701 //=============================================================================
2702 /*!
2703  * \brief Update objects depending on changed geom groups
2704  *
2705  * NPAL16168: geometrical group edition from a submesh don't modify mesh computation
2706  * issue 0020210: Update of a smesh group after modification of the associated geom group
2707  */
2708 //=============================================================================
2709
2710 void SMESH_Mesh_i::CheckGeomGroupModif()
2711 {
2712   // remove sub-meshes referring a removed sub-shapes (if main shape still exists)
2713   SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
2714   GEOM::GEOM_Object_var  mainGO = GetShapeToMesh();
2715   SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( SMESH::SMESH_Mesh_var( _this() ));
2716   if ( !mainGO->_is_nil() && !meshSO->_is_nil() )
2717   {
2718     SALOMEDS::SObject_wrap rootSO, geomRefSO, geomSO;
2719     for ( CORBA::Long tag = SMESH::Tag_FirstSubMesh; tag <= SMESH::Tag_LastSubMesh; ++tag )
2720       if ( meshSO->FindSubObject( tag, rootSO.inout() ))
2721       {
2722         int nbValid = 0, nbRemoved = 0;
2723         SALOMEDS::ChildIterator_wrap chItr = _gen_i->getStudyServant()->NewChildIterator( rootSO );
2724         for ( ; chItr->More(); chItr->Next() )
2725         {
2726           SALOMEDS::SObject_wrap smSO = chItr->Value(); // sub-mesh SO
2727           if ( !smSO->_is_nil() &&
2728                smSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
2729                geomRefSO->ReferencedObject( geomSO.inout() )) // find geometry by reference
2730           {
2731             CORBA::Object_var  geomObj = _gen_i->SObjectToObject( geomSO );
2732             GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( geomObj );
2733             if ( !geom->_non_existent() )
2734             {
2735               ++nbValid;
2736               continue; // keep the sub-mesh
2737             }
2738           }
2739           CORBA::Object_var     smObj = _gen_i->SObjectToObject( smSO );
2740           SMESH::SMESH_subMesh_var sm = SMESH::SMESH_subMesh::_narrow( smObj );
2741           if ( !sm->_is_nil() && !sm->_non_existent() )
2742           {
2743             GEOM::GEOM_Object_var smGeom = sm->GetSubShape();
2744             if ( smGeom->_is_nil() )
2745             {
2746               RemoveSubMesh( sm );
2747               ++nbRemoved;
2748             }
2749           }
2750           else
2751           {
2752             if ( _preMeshInfo )
2753               _preMeshInfo->ForgetAllData(); // unknown hypothesis modified
2754             builder->RemoveObjectWithChildren( smSO ); // sub-shape removed before loading SMESH
2755             ++nbRemoved;
2756           }
2757         }
2758         if ( /*nbRemoved > 0 &&*/ nbValid == 0 )
2759           builder->RemoveObjectWithChildren( rootSO );
2760       }
2761   }
2762
2763   // check for removed sub-shapes and convert geom dependent groups into standalone ones
2764   std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
2765   while ( i_gr != _mapGroups.end())
2766   {
2767     SMESH::SMESH_GroupBase_ptr group = i_gr->second;
2768     ++i_gr;
2769     SALOMEDS::SObject_wrap        groupSO = _gen_i->ObjectToSObject( group ), refSO, geomSO;
2770     SMESH::SMESH_GroupOnGeom_var   onGeom = SMESH::SMESH_GroupOnGeom::_narrow  ( group );
2771     SMESH::SMESH_GroupOnFilter_var onFilt = SMESH::SMESH_GroupOnFilter::_narrow( group );
2772     bool isValidGeom = false;
2773     if ( !onGeom->_is_nil() )
2774     {
2775       isValidGeom = ( ! GEOM::GEOM_Object_var( onGeom->GetShape() )->_is_nil() ); // check TopoDS
2776       if ( !isValidGeom ) // check reference
2777       {
2778         isValidGeom = ( ! groupSO->_is_nil() &&
2779                         groupSO->FindSubObject( SMESH::Tag_RefOnShape, refSO.inout() ) &&
2780                         refSO->ReferencedObject( geomSO.inout() ) &&
2781                         ! geomSO->_is_nil() &&
2782                         !CORBA::is_nil( CORBA::Object_var( geomSO->GetObject() )));
2783       }
2784     }
2785     else if ( !onFilt->_is_nil() )
2786     {
2787       isValidGeom = isValidGeomFilter( onFilt->GetFilter() );
2788     }
2789     else // standalone
2790     {
2791       isValidGeom = ( !groupSO->_is_nil() &&
2792                       !groupSO->FindSubObject( SMESH::Tag_RefOnShape, refSO.inout() ));
2793     }
2794     if ( !isValidGeom )
2795     {
2796       if ( !IsLoaded() || group->IsEmpty() )
2797       {
2798         RemoveGroup( group );
2799       }
2800       else if ( !onGeom->_is_nil() || !onFilt->_is_nil() )
2801       {
2802         SMESH::SMESH_Group_var ( ConvertToStandalone( group ));
2803       }
2804       else // is it possible?
2805       {
2806         builder->RemoveObjectWithChildren( refSO );
2807       }
2808     }
2809   }
2810
2811
2812   if ( !_impl->HasShapeToMesh() ) return;
2813
2814   CORBA::Long nbEntities = NbNodes() + NbElements();
2815
2816   // Check if group contents changed
2817
2818   typedef map< string, TopoDS_Shape > TEntry2Geom;
2819   TEntry2Geom newGroupContents;
2820
2821   list<TGeomGroupData>::iterator
2822     data = _geomGroupData.begin(), dataEnd = _geomGroupData.end();
2823   for ( ; data != dataEnd; ++data )
2824   {
2825     pair< TEntry2Geom::iterator, bool > it_new =
2826       newGroupContents.insert( make_pair( data->_groupEntry, TopoDS_Shape() ));
2827     bool processedGroup    = !it_new.second;
2828     TopoDS_Shape& newShape = it_new.first->second;
2829     if ( !processedGroup )
2830       newShape = newGroupShape( *data, ONLY_IF_CHANGED );
2831     if ( newShape.IsNull() )
2832       continue; // no changes
2833
2834     if ( _preMeshInfo )
2835       _preMeshInfo->ForgetOrLoad();
2836
2837     if ( processedGroup ) { // update group indices
2838       list<TGeomGroupData>::iterator data2 = data;
2839       for ( --data2; data2->_groupEntry != data->_groupEntry; --data2) {}
2840       data->_indices = data2->_indices;
2841     }
2842
2843     // Update SMESH objects according to new GEOM group contents
2844
2845     SMESH::SMESH_subMesh_var submesh = SMESH::SMESH_subMesh::_narrow( data->_smeshObject );
2846     if ( !submesh->_is_nil() ) // -------------- Sub mesh ---------------------
2847     {
2848       int oldID = submesh->GetId();
2849       if ( !_mapSubMeshIor.count( oldID ))
2850         continue;
2851       TopoDS_Shape oldShape = _mapSubMesh[oldID]->GetSubShape();
2852
2853       // update hypotheses
2854       list <const SMESHDS_Hypothesis * > hyps = _impl->GetHypothesisList(oldShape);
2855       list <const SMESHDS_Hypothesis * >::iterator hypIt;
2856       for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2857       {
2858         _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
2859         _impl->AddHypothesis   ( newShape, (*hypIt)->GetID());
2860       }
2861       // care of submeshes
2862       SMESH_subMesh* newSubmesh = _impl->GetSubMesh( newShape );
2863       int newID = newSubmesh->GetId();
2864       if ( newID != oldID ) {
2865         _mapSubMesh   [ newID ] = newSubmesh;
2866         _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2867         _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2868         _mapSubMesh.   erase(oldID);
2869         _mapSubMesh_i. erase(oldID);
2870         _mapSubMeshIor.erase(oldID);
2871         _mapSubMesh_i [ newID ]->changeLocalId( newID );
2872       }
2873       continue;
2874     }
2875
2876     SMESH::SMESH_GroupOnGeom_var smeshGroup =
2877       SMESH::SMESH_GroupOnGeom::_narrow( data->_smeshObject );
2878     if ( !smeshGroup->_is_nil() ) // ------------ GROUP -----------------------
2879     {
2880       SMESH_GroupOnGeom_i* group_i = SMESH::DownCast<SMESH_GroupOnGeom_i*>( smeshGroup );
2881       if ( group_i ) {
2882         ::SMESH_Group* group = _impl->GetGroup( group_i->GetLocalID() );
2883         SMESHDS_GroupOnGeom* ds = static_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() );
2884         ds->SetShape( newShape );
2885       }
2886       continue;
2887     }
2888
2889     SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( data->_smeshObject );
2890     if ( !mesh->_is_nil() ) // -------------- MESH ----------------------------
2891     {
2892       // Remove groups and submeshes basing on removed sub-shapes
2893
2894       TopTools_MapOfShape newShapeMap;
2895       TopoDS_Iterator shapeIt( newShape );
2896       for ( ; shapeIt.More(); shapeIt.Next() )
2897         newShapeMap.Add( shapeIt.Value() );
2898
2899       SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
2900       for ( shapeIt.Initialize( meshDS->ShapeToMesh() ); shapeIt.More(); shapeIt.Next() )
2901       {
2902         if ( newShapeMap.Contains( shapeIt.Value() ))
2903           continue;
2904         TopTools_IndexedMapOfShape oldShapeMap;
2905         TopExp::MapShapes( shapeIt.Value(), oldShapeMap );
2906         for ( int i = 1; i <= oldShapeMap.Extent(); ++i )
2907         {
2908           const TopoDS_Shape& oldShape = oldShapeMap(i);
2909           int oldInd = meshDS->ShapeToIndex( oldShape );
2910           // -- submeshes --
2911           map<int, SMESH::SMESH_subMesh_ptr>::iterator i_smIor = _mapSubMeshIor.find( oldInd );
2912           if ( i_smIor != _mapSubMeshIor.end() ) {
2913             RemoveSubMesh( i_smIor->second ); // one submesh per shape index
2914           }
2915           // --- groups ---
2916           map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.begin();
2917           for ( ; i_grp != _mapGroups.end(); ++i_grp )
2918           {
2919             // check if a group bases on oldInd shape
2920             SMESHDS_GroupOnGeom* grpOnGeom = 0;
2921             if ( ::SMESH_Group* g = _impl->GetGroup( i_grp->first ))
2922               grpOnGeom = dynamic_cast<SMESHDS_GroupOnGeom*>( g->GetGroupDS() );
2923             if ( grpOnGeom && oldShape.IsSame( grpOnGeom->GetShape() ))
2924             { // remove
2925               RemoveGroup( i_grp->second ); // several groups can base on same shape
2926               i_grp = _mapGroups.begin(); // _mapGroups changed - restart iteration
2927             }
2928           }
2929         }
2930       }
2931       // Reassign hypotheses and update groups after setting the new shape to mesh
2932
2933       // collect anassigned hypotheses
2934       typedef list< pair< TIndexedShape, list<const SMESHDS_Hypothesis*> > > TShapeHypList;
2935       list <const SMESHDS_Hypothesis * >::const_iterator hypIt;
2936       TShapeHypList assignedHyps;
2937       for ( int i = 1; i <= meshDS->MaxShapeIndex(); ++i )
2938       {
2939         const TopoDS_Shape& oldShape = meshDS->IndexToShape(i);
2940         list<const SMESHDS_Hypothesis*> hyps = meshDS->GetHypothesis( oldShape );// copy
2941         if ( !hyps.empty() ) {
2942           assignedHyps.push_back( make_pair( TIndexedShape(i,oldShape), hyps ));
2943           for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2944             _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
2945         }
2946       }
2947       // collect shapes supporting groups
2948       typedef list < pair< TIndexedShape, SMDSAbs_ElementType > > TShapeTypeList;
2949       TShapeTypeList groupData;
2950       const set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
2951       set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2952       for ( ; grIt != groups.end(); ++grIt )
2953       {
2954         if ( SMESHDS_GroupOnGeom* gog = dynamic_cast<SMESHDS_GroupOnGeom*>( *grIt ))
2955           groupData.push_back
2956             ( make_pair( TIndexedShape( gog->GetID(),gog->GetShape()), gog->GetType()));
2957       }
2958       // set new shape to mesh -> DS of sub-meshes and geom groups is deleted
2959       _impl->Clear();
2960       _impl->ShapeToMesh( TopoDS_Shape() ); // IPAL52730
2961       _impl->ShapeToMesh( newShape );
2962
2963       // reassign hypotheses
2964       TShapeHypList::iterator indS_hyps = assignedHyps.begin();
2965       for ( ; indS_hyps != assignedHyps.end(); ++indS_hyps )
2966       {
2967         TIndexedShape&                   geom = indS_hyps->first;
2968         list<const SMESHDS_Hypothesis*>& hyps = indS_hyps->second;
2969         int oldID = geom._index;
2970         int newID = meshDS->ShapeToIndex( geom._shape );
2971         if ( oldID == 1 ) { // main shape
2972           newID = 1;
2973           geom._shape = newShape;
2974         }
2975         if ( !newID )
2976           continue;
2977         for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2978           _impl->AddHypothesis( geom._shape, (*hypIt)->GetID());
2979         // care of sub-meshes
2980         SMESH_subMesh* newSubmesh = _impl->GetSubMesh( geom._shape );
2981         if ( newID != oldID ) {
2982           _mapSubMesh   [ newID ] = newSubmesh;
2983           _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2984           _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2985           _mapSubMesh.   erase(oldID);
2986           _mapSubMesh_i. erase(oldID);
2987           _mapSubMeshIor.erase(oldID);
2988           _mapSubMesh_i [ newID ]->changeLocalId( newID );
2989         }
2990       }
2991       // recreate groups
2992       TShapeTypeList::iterator geomType = groupData.begin();
2993       for ( ; geomType != groupData.end(); ++geomType )
2994       {
2995         const TIndexedShape& geom = geomType->first;
2996         int oldID = geom._index;
2997         if ( _mapGroups.find( oldID ) == _mapGroups.end() )
2998           continue;
2999         // get group name
3000         SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( _mapGroups[oldID] );
3001         CORBA::String_var      name    = groupSO->GetName();
3002         // update
3003         if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>(_mapGroups[oldID]))
3004           if ( SMESH_Group* group = _impl->AddGroup( geomType->second, name.in(),
3005                                                      /*id=*/-1, geom._shape ))
3006             group_i->changeLocalId( group->GetID() );
3007       }
3008
3009       break; // everything has been updated
3010
3011     } // update mesh
3012   } // loop on group data
3013
3014   // Update icons
3015
3016   CORBA::Long newNbEntities = NbNodes() + NbElements();
3017   list< SALOMEDS::SObject_wrap > soToUpdateIcons;
3018   if ( newNbEntities != nbEntities )
3019   {
3020     // Add all SObjects with icons to soToUpdateIcons
3021     soToUpdateIcons.push_back( _gen_i->ObjectToSObject( _this() )); // mesh
3022
3023     for (map<int, SMESH::SMESH_subMesh_ptr>::iterator i_sm = _mapSubMeshIor.begin();
3024          i_sm != _mapSubMeshIor.end(); ++i_sm ) // submeshes
3025       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( i_sm->second ));
3026
3027     for ( map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
3028           i_gr != _mapGroups.end(); ++i_gr ) // groups
3029       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( i_gr->second ));
3030   }
3031
3032   list< SALOMEDS::SObject_wrap >::iterator so = soToUpdateIcons.begin();
3033   for ( ; so != soToUpdateIcons.end(); ++so )
3034     _gen_i->SetPixMap( *so, "ICON_SMESH_TREE_MESH_WARN" );
3035 }
3036
3037 //=============================================================================
3038 /*!
3039  * \brief Create standalone group from a group on geometry or filter
3040  */
3041 //=============================================================================
3042
3043 SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupBase_ptr theGroup )
3044   throw (SALOME::SALOME_Exception)
3045 {
3046   SMESH::SMESH_Group_var aGroup;
3047
3048   SMESH_TRY;
3049
3050   if ( _preMeshInfo )
3051     _preMeshInfo->FullLoadFromFile();
3052
3053   if ( theGroup->_is_nil() )
3054     return aGroup._retn();
3055
3056   SMESH_GroupBase_i* aGroupToRem = SMESH::DownCast<SMESH_GroupBase_i*>( theGroup );
3057   if ( !aGroupToRem )
3058     return aGroup._retn();
3059
3060   const bool isOnFilter = ( SMESH::DownCast< SMESH_GroupOnFilter_i* > ( theGroup ));
3061
3062   const int anId = aGroupToRem->GetLocalID();
3063   if ( !_impl->ConvertToStandalone( anId ) )
3064     return aGroup._retn();
3065   removeGeomGroupData( theGroup );
3066
3067   SMESH_GroupBase_i* aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
3068
3069   // remove old instance of group from own map
3070   { SMESH::SMESH_GroupBase_var var( _mapGroups[anId] ); } // decref CORBA object
3071   _mapGroups.erase( anId );
3072
3073   SALOMEDS::StudyBuilder_var builder;
3074   SALOMEDS::SObject_wrap     aGroupSO;
3075   SALOMEDS::Study_var        aStudy = SMESH_Gen_i::getStudyServant();
3076   if ( !aStudy->_is_nil() ) {
3077     builder  = aStudy->NewBuilder();
3078     aGroupSO = _gen_i->ObjectToSObject( theGroup );
3079     if ( !aGroupSO->_is_nil() )
3080     {
3081       // remove reference to geometry
3082       SALOMEDS::ChildIterator_wrap chItr = aStudy->NewChildIterator(aGroupSO);
3083       for ( ; chItr->More(); chItr->Next() )
3084       {
3085         // Remove group's child SObject
3086         SALOMEDS::SObject_wrap so = chItr->Value();
3087         builder->RemoveObject( so );
3088       }
3089       // Update Python script
3090       TPythonDump() << aGroupSO << " = " << SMESH::SMESH_Mesh_var(_this())
3091                     << ".ConvertToStandalone( " << aGroupSO << " )";
3092
3093       // change icon of Group on Filter
3094       if ( isOnFilter )
3095       {
3096         // SMESH::array_of_ElementType_var elemTypes = aGroupImpl->GetTypes();
3097         // const int isEmpty = ( elemTypes->length() == 0 );
3098         // if ( !isEmpty )
3099         {
3100           SALOMEDS::GenericAttribute_wrap anAttr =
3101             builder->FindOrCreateAttribute( aGroupSO, "AttributePixMap" );
3102           SALOMEDS::AttributePixMap_wrap pm = anAttr;
3103           pm->SetPixMap( "ICON_SMESH_TREE_GROUP" );
3104         }
3105       }
3106     }
3107   }
3108
3109   // remember new group in own map
3110   aGroup = SMESH::SMESH_Group::_narrow( aGroupImpl->_this() );
3111   _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
3112
3113   // register CORBA object for persistence
3114   _gen_i->RegisterObject( aGroup );
3115
3116   CORBA::String_var ior = _gen_i->GetORB()->object_to_string( aGroup );
3117   builder->SetIOR( aGroupSO, ior.in() ); //  == aGroup->Register();
3118   //aGroup->Register();
3119   aGroupToRem->UnRegister();
3120
3121   SMESH_CATCH( SMESH::throwCorbaException );
3122
3123   return aGroup._retn();
3124 }
3125
3126 //================================================================================
3127 /*!
3128  * \brief Create a sub-mesh on a given sub-shape
3129  */
3130 //================================================================================
3131
3132 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::createSubMesh( GEOM::GEOM_Object_ptr theSubShapeObject )
3133 {
3134   if(MYDEBUG) MESSAGE( "createSubMesh" );
3135   TopoDS_Shape  myLocSubShape = _gen_i->GeomObjectToShape(theSubShapeObject);
3136   ::SMESH_subMesh * mySubMesh = _impl->GetSubMesh(myLocSubShape);
3137   int               subMeshId = 0;
3138
3139   SMESH_subMesh_i * subMeshServant;
3140   if ( mySubMesh )
3141   {
3142     subMeshId = mySubMesh->GetId();
3143     subMeshServant = new SMESH_subMesh_i(myPOA, _gen_i, this, subMeshId);
3144   }
3145   else // "invalid sub-mesh"
3146   {
3147     // The invalid sub-mesh is created for the case where a valid sub-shape not found
3148     // by SMESH_Gen_i::CopyMeshWithGeom(). The invalid sub-mesh has GetId() < 0.
3149     if ( _mapSubMesh.empty() )
3150       subMeshId = -1;
3151     else
3152       subMeshId = _mapSubMesh.begin()->first - 1;
3153     subMeshServant = new SMESH_Invalid_subMesh_i(myPOA, _gen_i, this, subMeshId, theSubShapeObject);
3154   }
3155
3156   SMESH::SMESH_subMesh_var subMesh = subMeshServant->_this();
3157
3158   _mapSubMesh   [subMeshId] = mySubMesh;
3159   _mapSubMesh_i [subMeshId] = subMeshServant;
3160   _mapSubMeshIor[subMeshId] = SMESH::SMESH_subMesh::_duplicate( subMesh );
3161
3162   subMeshServant->Register();
3163
3164   // register CORBA object for persistence
3165   int nextId = _gen_i->RegisterObject( subMesh );
3166   if(MYDEBUG) { MESSAGE( "Add submesh to map with id = "<< nextId); }
3167   else        { nextId = 0; } // avoid "unused variable" warning
3168
3169   // to track changes of GEOM groups
3170   if ( subMeshId > 0 )
3171     addGeomGroupData( theSubShapeObject, subMesh );
3172
3173   return subMesh._retn();
3174 }
3175
3176 //================================================================================
3177 /*!
3178  * \brief Return an existing sub-mesh based on a sub-shape with the given ID
3179  */
3180 //================================================================================
3181
3182 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::getSubMesh(int shapeID)
3183 {
3184   map<int, SMESH::SMESH_subMesh_ptr>::iterator it = _mapSubMeshIor.find( shapeID );
3185   if ( it == _mapSubMeshIor.end() )
3186     return SMESH::SMESH_subMesh::_nil();
3187
3188   return SMESH::SMESH_subMesh::_duplicate( (*it).second );
3189 }
3190
3191 //================================================================================
3192 /*!
3193  * \brief Remove a sub-mesh based on the given sub-shape
3194  */
3195 //================================================================================
3196
3197 bool SMESH_Mesh_i::removeSubMesh (SMESH::SMESH_subMesh_ptr theSubMesh,
3198                                   GEOM::GEOM_Object_ptr    theSubShapeObject )
3199 {
3200   bool isHypChanged = false;
3201   if ( theSubMesh->_is_nil() /*|| theSubShapeObject->_is_nil()*/ )
3202     return isHypChanged;
3203
3204   const int subMeshId = theSubMesh->GetId();
3205
3206   if ( theSubShapeObject->_is_nil() )  // not published shape (IPAL13617)
3207   {
3208     SMESH_subMesh* sm;
3209     if (( _mapSubMesh.count( subMeshId )) &&
3210         ( sm = _impl->GetSubMeshContaining( subMeshId )))
3211     {
3212       TopoDS_Shape S = sm->GetSubShape();
3213       if ( !S.IsNull() )
3214       {
3215         list<const SMESHDS_Hypothesis*> hyps = _impl->GetHypothesisList( S );
3216         isHypChanged = !hyps.empty();
3217         if ( isHypChanged && _preMeshInfo )
3218           _preMeshInfo->ForgetOrLoad();
3219         list<const SMESHDS_Hypothesis*>::const_iterator hyp = hyps.begin();
3220         for ( ; hyp != hyps.end(); ++hyp )
3221           _impl->RemoveHypothesis(S, (*hyp)->GetID());
3222       }
3223     }
3224   }
3225   else
3226   {
3227     try {
3228       SMESH::ListOfHypothesis_var aHypList = GetHypothesisList( theSubShapeObject );
3229       isHypChanged = ( aHypList->length() > 0 );
3230       for ( int i = 0, n = aHypList->length(); i < n; i++ ) {
3231         removeHypothesis( theSubShapeObject, aHypList[i] );
3232       }
3233     }
3234     catch( const SALOME::SALOME_Exception& ) {
3235       INFOS("SMESH_Mesh_i::removeSubMesh(): exception caught!");
3236     }
3237     removeGeomGroupData( theSubShapeObject );
3238   }
3239
3240   // remove a servant
3241   std::map<int, SMESH_subMesh_i*>::iterator id_smi = _mapSubMesh_i.find( subMeshId );
3242   if ( id_smi != _mapSubMesh_i.end() )
3243     id_smi->second->UnRegister();
3244
3245   // remove a CORBA object
3246   std::map<int, SMESH::SMESH_subMesh_ptr>::iterator id_smptr = _mapSubMeshIor.find( subMeshId );
3247   if ( id_smptr != _mapSubMeshIor.end() )
3248     SMESH::SMESH_subMesh_var( id_smptr->second );
3249
3250   _mapSubMesh.erase(subMeshId);
3251   _mapSubMesh_i.erase(subMeshId);
3252   _mapSubMeshIor.erase(subMeshId);
3253
3254   return isHypChanged;
3255 }
3256
3257 //================================================================================
3258 /*!
3259  * \brief Create a group. Group type depends on given arguments
3260  */
3261 //================================================================================
3262
3263 SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType        theElemType,
3264                                                       const char*               theName,
3265                                                       const int                 theID,
3266                                                       const TopoDS_Shape&       theShape,
3267                                                       const SMESH_PredicatePtr& thePredicate )
3268 {
3269   std::string newName;
3270   if ( !theName || !theName[0] )
3271   {
3272     std::set< std::string > presentNames;
3273     std::map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator i_gr = _mapGroups.begin();
3274     for ( ; i_gr != _mapGroups.end(); ++i_gr )
3275     {
3276       CORBA::String_var name = i_gr->second->GetName();
3277       presentNames.insert( name.in() );
3278     }
3279     do {
3280       newName = "noname_Group_" + SMESH_Comment( presentNames.size() + 1 );
3281     } while ( !presentNames.insert( newName ).second );
3282     theName = newName.c_str();
3283   }
3284   SMESH::SMESH_GroupBase_var aGroup;
3285   if ( SMESH_Group* g = _impl->AddGroup( (SMDSAbs_ElementType)theElemType, theName,
3286                                          theID, theShape, thePredicate ))
3287   {
3288     int anId = g->GetID();
3289     SMESH_GroupBase_i* aGroupImpl;
3290     if ( !theShape.IsNull() )
3291       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
3292     else if ( thePredicate )
3293       aGroupImpl = new SMESH_GroupOnFilter_i( SMESH_Gen_i::GetPOA(), this, anId );
3294     else
3295       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
3296
3297     aGroup = aGroupImpl->_this();
3298     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
3299     aGroupImpl->Register();
3300
3301     // register CORBA object for persistence
3302     int nextId = _gen_i->RegisterObject( aGroup );
3303     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
3304     else        { nextId = ( nextId > 0 ); } // avoid "unused variable" warning in release mode
3305
3306     // to track changes of GEOM groups
3307     if ( !theShape.IsNull() ) {
3308       GEOM::GEOM_Object_var geom = _gen_i->ShapeToGeomObject( theShape );
3309       addGeomGroupData( geom, aGroup );
3310     }
3311   }
3312   return aGroup._retn();
3313 }
3314
3315 //=============================================================================
3316 /*!
3317  * SMESH_Mesh_i::removeGroup
3318  *
3319  * Should be called by ~SMESH_Group_i()
3320  */
3321 //=============================================================================
3322
3323 void SMESH_Mesh_i::removeGroup( const int theId )
3324 {
3325   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::removeGroup()" );
3326   if ( _mapGroups.find( theId ) != _mapGroups.end() ) {
3327     SMESH::SMESH_GroupBase_var group = _mapGroups[theId];
3328     _mapGroups.erase( theId );
3329     removeGeomGroupData( group );
3330     if ( !_impl->RemoveGroup( theId ))
3331     {
3332       // it seems to be a call up from _impl caused by hyp modification (issue 0020918)
3333       RemoveGroup( group );
3334     }
3335     group->UnRegister();
3336   }
3337 }
3338
3339 //================================================================================
3340 /*!
3341  * \brief Return a log that can be used to move another mesh to the same state as this one
3342  */
3343 //================================================================================
3344
3345 SMESH::log_array * SMESH_Mesh_i::GetLog(CORBA::Boolean clearAfterGet)
3346   throw(SALOME::SALOME_Exception)
3347 {
3348   SMESH::log_array_var aLog;
3349
3350   SMESH_TRY;
3351   if ( _preMeshInfo )
3352     _preMeshInfo->FullLoadFromFile();
3353
3354   list < SMESHDS_Command * >logDS = _impl->GetLog();
3355   aLog = new SMESH::log_array;
3356   int indexLog = 0;
3357   int lg = logDS.size();
3358   aLog->length(lg);
3359   list < SMESHDS_Command * >::iterator its = logDS.begin();
3360   while(its != logDS.end()){
3361     SMESHDS_Command *com = *its;
3362     int comType = com->GetType();
3363     int lgcom = com->GetNumber();
3364     const list < int >&intList = com->GetIndexes();
3365     int inum = intList.size();
3366     list < int >::const_iterator ii = intList.begin();
3367     const list < double >&coordList = com->GetCoords();
3368     int rnum = coordList.size();
3369     list < double >::const_iterator ir = coordList.begin();
3370     aLog[indexLog].commandType = comType;
3371     aLog[indexLog].number = lgcom;
3372     aLog[indexLog].coords.length(rnum);
3373     aLog[indexLog].indexes.length(inum);
3374     for(int i = 0; i < rnum; i++){
3375       aLog[indexLog].coords[i] = *ir;
3376       ir++;
3377     }
3378     for(int i = 0; i < inum; i++){
3379       aLog[indexLog].indexes[i] = *ii;
3380       ii++;
3381     }
3382     indexLog++;
3383     its++;
3384   }
3385   if(clearAfterGet)
3386     _impl->ClearLog();
3387
3388   SMESH_CATCH( SMESH::throwCorbaException );
3389
3390   return aLog._retn();
3391 }
3392
3393 //================================================================================
3394 /*!
3395  * \brief Remove the log of commands
3396  */
3397 //================================================================================
3398
3399 void SMESH_Mesh_i::ClearLog() throw(SALOME::SALOME_Exception)
3400 {
3401   SMESH_TRY;
3402   _impl->ClearLog();
3403   SMESH_CATCH( SMESH::throwCorbaException );
3404 }
3405
3406 //================================================================================
3407 /*!
3408  * \brief Return a mesh ID
3409  */
3410 //================================================================================
3411
3412 CORBA::Long SMESH_Mesh_i::GetId()throw(SALOME::SALOME_Exception)
3413 {
3414   return _id;
3415 }
3416
3417 //=============================================================================
3418 namespace
3419 {
3420   //!< implementation of struct used to call methods of SMESH_Mesh_i from SMESH_Mesh
3421   // issue 0020918: groups removal is caused by hyp modification
3422   // issue 0021208: to forget not loaded mesh data at hyp modification
3423   struct TCallUp_i : public SMESH_Mesh::TCallUp
3424   {
3425     SMESH_Mesh_i* _mesh;
3426     TCallUp_i(SMESH_Mesh_i* mesh):_mesh(mesh) {}
3427     virtual void RemoveGroup (const int theGroupID) { _mesh->removeGroup( theGroupID ); }
3428     virtual void HypothesisModified( int hypID,
3429                                      bool updIcons) { _mesh->onHypothesisModified( hypID,
3430                                                                                    updIcons ); }
3431     virtual void Load ()                            { _mesh->Load(); }
3432     virtual bool IsLoaded()                         { return _mesh->IsLoaded(); }
3433   };
3434 }
3435
3436 //================================================================================
3437 /*!
3438  * \brief callback from _impl to
3439  *     1) forget not loaded mesh data (issue 0021208)
3440  *     2) mark hypothesis as valid
3441  */
3442 //================================================================================
3443
3444 void SMESH_Mesh_i::onHypothesisModified(int theHypID, bool theUpdateIcons)
3445 {
3446   if ( _preMeshInfo )
3447     _preMeshInfo->ForgetOrLoad();
3448
3449   if ( theUpdateIcons )
3450   {
3451     SMESH::SMESH_Mesh_var mesh = _this();
3452     _gen_i->UpdateIcons( mesh );
3453   }
3454
3455   if ( _nbInvalidHypos != 0 )
3456   {
3457     // mark a hypothesis as valid after edition
3458     int nbInvalid = 0;
3459     SALOMEDS::SComponent_wrap smeshComp = _gen_i->PublishComponent();
3460     SALOMEDS::SObject_wrap hypRoot;
3461     if ( !smeshComp->_is_nil() &&
3462          smeshComp->FindSubObject( _gen_i->GetHypothesisRootTag(), hypRoot.inout() ))
3463     {
3464       SALOMEDS::ChildIterator_wrap anIter = _gen_i->getStudyServant()->NewChildIterator( hypRoot );
3465       for ( ; anIter->More(); anIter->Next() )
3466       {
3467         SALOMEDS::SObject_wrap    hypSO = anIter->Value();
3468         CORBA::Object_var           obj = _gen_i->SObjectToObject( hypSO );
3469         SMESH::SMESH_Hypothesis_var hyp = SMESH::SMESH_Hypothesis::_narrow( obj );
3470         if ( !hyp->_is_nil() && hyp->GetId() == theHypID )
3471           _gen_i->HighLightInvalid( hyp, false );
3472         else
3473           nbInvalid += _gen_i->IsInvalid( hypSO );
3474       }
3475     }
3476     _nbInvalidHypos = nbInvalid;
3477   }
3478 }
3479
3480 //================================================================================
3481 /*!
3482  * \brief Set mesh implementation
3483  */
3484 //================================================================================
3485
3486 void SMESH_Mesh_i::SetImpl(::SMESH_Mesh * impl)
3487 {
3488   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::SetImpl");
3489   _impl = impl;
3490   if ( _impl )
3491     _impl->SetCallUp( new TCallUp_i(this));
3492 }
3493
3494 //=============================================================================
3495 /*!
3496  * Return a mesh implementation
3497  */
3498 //=============================================================================
3499
3500 ::SMESH_Mesh & SMESH_Mesh_i::GetImpl()
3501 {
3502   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::GetImpl()");
3503   return *_impl;
3504 }
3505
3506 //=============================================================================
3507 /*!
3508  * Return mesh editor
3509  */
3510 //=============================================================================
3511
3512 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditor()
3513   throw (SALOME::SALOME_Exception)
3514 {
3515   SMESH::SMESH_MeshEditor_var aMeshEdVar;
3516
3517   SMESH_TRY;
3518   if ( _preMeshInfo )
3519     _preMeshInfo->FullLoadFromFile();
3520
3521   // Create MeshEditor
3522   if ( !_editor )
3523     _editor = new SMESH_MeshEditor_i( this, false );
3524   aMeshEdVar = _editor->_this();
3525
3526   // Update Python script
3527   TPythonDump() << _editor << " = "
3528                 << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshEditor()";
3529
3530   SMESH_CATCH( SMESH::throwCorbaException );
3531
3532   return aMeshEdVar._retn();
3533 }
3534
3535 //=============================================================================
3536 /*!
3537  * Return mesh edition previewer
3538  */
3539 //=============================================================================
3540
3541 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditPreviewer()
3542   throw (SALOME::SALOME_Exception)
3543 {
3544   SMESH::SMESH_MeshEditor_var aMeshEdVar;
3545
3546   SMESH_TRY;
3547   if ( _preMeshInfo )
3548     _preMeshInfo->FullLoadFromFile();
3549
3550   if ( !_previewEditor )
3551     _previewEditor = new SMESH_MeshEditor_i( this, true );
3552   aMeshEdVar = _previewEditor->_this();
3553
3554   SMESH_CATCH( SMESH::throwCorbaException );
3555
3556   return aMeshEdVar._retn();
3557 }
3558
3559 //================================================================================
3560 /*!
3561  * \brief Return true if the mesh has been edited since a last total re-compute
3562  *        and those modifications may prevent successful partial re-compute
3563  */
3564 //================================================================================
3565
3566 CORBA::Boolean SMESH_Mesh_i::HasModificationsToDiscard() throw(SALOME::SALOME_Exception)
3567 {
3568   Unexpect aCatch(SALOME_SalomeException);
3569   return _impl->HasModificationsToDiscard();
3570 }
3571
3572 //================================================================================
3573 /*!
3574  * \brief Return a random unique color
3575  */
3576 //================================================================================
3577
3578 static SALOMEDS::Color getUniqueColor( const std::list<SALOMEDS::Color>& theReservedColors )
3579 {
3580   const int MAX_ATTEMPTS = 100;
3581   int cnt = 0;
3582   double tolerance = 0.5;
3583   SALOMEDS::Color col;
3584
3585   bool ok = false;
3586   while ( !ok ) {
3587     // generate random color
3588     double red    = (double)rand() / RAND_MAX;
3589     double green  = (double)rand() / RAND_MAX;
3590     double blue   = (double)rand() / RAND_MAX;
3591     // check existence in the list of the existing colors
3592     bool matched = false;
3593     std::list<SALOMEDS::Color>::const_iterator it;
3594     for ( it = theReservedColors.begin(); it != theReservedColors.end() && !matched; ++it ) {
3595       SALOMEDS::Color color = *it;
3596       double tol = fabs( color.R - red ) + fabs( color.G - green ) + fabs( color.B  - blue  );
3597       matched = tol < tolerance;
3598     }
3599     if ( (cnt+1) % 20 == 0 ) tolerance = tolerance/2;
3600     ok = ( ++cnt == MAX_ATTEMPTS ) || !matched;
3601     col.R = red;
3602     col.G = green;
3603     col.B = blue;
3604   }
3605   return col;
3606 }
3607
3608 //=============================================================================
3609 /*!
3610  * Set auto-color mode. If it is on, groups get unique random colors
3611  */
3612 //=============================================================================
3613
3614 void SMESH_Mesh_i::SetAutoColor(CORBA::Boolean theAutoColor) throw(SALOME::SALOME_Exception)
3615 {
3616   Unexpect aCatch(SALOME_SalomeException);
3617   _impl->SetAutoColor(theAutoColor);
3618
3619   TPythonDump pyDump; // not to dump group->SetColor() from below code
3620   pyDump << SMESH::SMESH_Mesh_var(_this()) <<".SetAutoColor( "<<theAutoColor<<" )";
3621
3622   std::list<SALOMEDS::Color> aReservedColors;
3623   map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.begin();
3624   for ( ; it != _mapGroups.end(); it++ ) {
3625     if ( CORBA::is_nil( it->second )) continue;
3626     SALOMEDS::Color aColor = getUniqueColor( aReservedColors );
3627     it->second->SetColor( aColor );
3628     aReservedColors.push_back( aColor );
3629   }
3630 }
3631
3632 //=============================================================================
3633 /*!
3634  * Return true if auto-color mode is on
3635  */
3636 //=============================================================================
3637
3638 CORBA::Boolean SMESH_Mesh_i::GetAutoColor() throw(SALOME::SALOME_Exception)
3639 {
3640   Unexpect aCatch(SALOME_SalomeException);
3641   return _impl->GetAutoColor();
3642 }
3643
3644 //=============================================================================
3645 /*!
3646  *  Check if there are groups with equal names
3647  */
3648 //=============================================================================
3649
3650 CORBA::Boolean SMESH_Mesh_i::HasDuplicatedGroupNamesMED()
3651 {
3652   return _impl->HasDuplicatedGroupNamesMED();
3653 }
3654
3655 //================================================================================
3656 /*!
3657  * \brief Care of a file before exporting mesh into it
3658  */
3659 //================================================================================
3660
3661 void SMESH_Mesh_i::PrepareForWriting (const char* file, bool overwrite)
3662 {
3663   SMESH_File aFile( file, false );
3664   SMESH_Comment msg;
3665   if ( aFile.exists() ) {
3666     // existing filesystem node
3667     if ( !aFile.isDirectory() ) {
3668       if ( aFile.openForWriting() ) {
3669         if ( overwrite && ! aFile.remove()) {
3670           msg << "Can't replace " << aFile.getName();
3671         }
3672       } else {
3673         msg << "Can't write into " << aFile.getName();
3674       }
3675     } else {
3676       msg << "Location " << aFile.getName() << " is not a file";
3677     }
3678   }
3679   else {
3680     // nonexisting file; check if it can be created
3681     if ( !aFile.openForWriting() ) {
3682       msg << "You cannot create the file "
3683           << aFile.getName()
3684           << ". Check the directory existence and access rights";
3685     }
3686     aFile.remove();
3687   }
3688
3689   if ( !msg.empty() )
3690   {
3691     msg << ".";
3692     THROW_SALOME_CORBA_EXCEPTION(msg.c_str(), SALOME::BAD_PARAM);
3693   }
3694 }
3695
3696 //================================================================================
3697 /*!
3698  * \brief Prepare a file for export and pass names of mesh groups from study to mesh DS
3699  *  \param file - file name
3700  *  \param overwrite - to erase the file or not
3701  *  \retval string - mesh name
3702  */
3703 //================================================================================
3704
3705 string SMESH_Mesh_i::prepareMeshNameAndGroups(const char*    file,
3706                                               CORBA::Boolean overwrite)
3707 {
3708   // Perform Export
3709   PrepareForWriting(file, overwrite);
3710   string aMeshName = "Mesh";
3711   SALOMEDS::Study_var aStudy = SMESH_Gen_i::getStudyServant();
3712   if ( !aStudy->_is_nil() ) {
3713     SALOMEDS::SObject_wrap aMeshSO = _gen_i->ObjectToSObject(  _this() );
3714     if ( !aMeshSO->_is_nil() ) {
3715       CORBA::String_var name = aMeshSO->GetName();
3716       aMeshName = name;
3717       // asv : 27.10.04 : fix of 6903: check for StudyLocked before adding attributes
3718       if ( !aStudy->GetProperties()->IsLocked() )
3719       {
3720         SALOMEDS::GenericAttribute_wrap anAttr;
3721         SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder();
3722         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeExternalFileDef");
3723         SALOMEDS::AttributeExternalFileDef_wrap aFileName = anAttr;
3724         ASSERT(!aFileName->_is_nil());
3725         aFileName->SetValue(file);
3726         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeFileType");
3727         SALOMEDS::AttributeFileType_wrap aFileType = anAttr;
3728         ASSERT(!aFileType->_is_nil());
3729         aFileType->SetValue("FICHIERMED");
3730       }
3731     }
3732   }
3733   // Update Python script
3734   // set name of mesh before export
3735   TPythonDump() << _gen_i << ".SetName("
3736                 << SMESH::SMESH_Mesh_var(_this()) << ", '" << aMeshName.c_str() << "')";
3737
3738   // check names of groups
3739   checkGroupNames();
3740
3741   return aMeshName;
3742 }
3743
3744 //================================================================================
3745 /*!
3746  * \brief Export to MED file
3747  */
3748 //================================================================================
3749
3750 void SMESH_Mesh_i::ExportMED(const char*        file,
3751                              CORBA::Boolean     auto_groups,
3752                              CORBA::Long        version,
3753                              CORBA::Boolean     overwrite,
3754                              CORBA::Boolean     autoDimension)
3755   throw(SALOME::SALOME_Exception)
3756 {
3757   //MESSAGE("MED minor version: "<< minor);
3758   SMESH_TRY;
3759   if ( _preMeshInfo )
3760     _preMeshInfo->FullLoadFromFile();
3761
3762   string aMeshName = prepareMeshNameAndGroups(file, overwrite);
3763   _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version, 0, autoDimension );
3764
3765   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportMED( r'"
3766                 << file << "', "
3767                 << "auto_groups=" <<auto_groups << ", "
3768                 << "minor=" << version <<  ", "
3769                 << "overwrite=" << overwrite << ", "
3770                 << "meshPart=None, "
3771                 << "autoDimension=" << autoDimension << " )";
3772
3773   SMESH_CATCH( SMESH::throwCorbaException );
3774 }
3775
3776 //================================================================================
3777 /*!
3778  * \brief Export a mesh to a SAUV file
3779  */
3780 //================================================================================
3781
3782 void SMESH_Mesh_i::ExportSAUV (const char* file,
3783                                CORBA::Boolean auto_groups)
3784   throw(SALOME::SALOME_Exception)
3785 {
3786   Unexpect aCatch(SALOME_SalomeException);
3787   if ( _preMeshInfo )
3788     _preMeshInfo->FullLoadFromFile();
3789
3790   string aMeshName = prepareMeshNameAndGroups(file, true);
3791   TPythonDump() << SMESH::SMESH_Mesh_var( _this())
3792                 << ".ExportSAUV( r'" << file << "', " << auto_groups << " )";
3793   _impl->ExportSAUV(file, aMeshName.c_str(), auto_groups);
3794 }
3795
3796
3797 //================================================================================
3798 /*!
3799  * \brief Export a mesh to a DAT file
3800  */
3801 //================================================================================
3802
3803 void SMESH_Mesh_i::ExportDAT (const char *file)
3804   throw(SALOME::SALOME_Exception)
3805 {
3806   Unexpect aCatch(SALOME_SalomeException);
3807   if ( _preMeshInfo )
3808     _preMeshInfo->FullLoadFromFile();
3809
3810   // Update Python script
3811   // check names of groups
3812   checkGroupNames();
3813   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportDAT( r'" << file << "' )";
3814
3815   // Perform Export
3816   PrepareForWriting(file);
3817   _impl->ExportDAT(file);
3818 }
3819
3820 //================================================================================
3821 /*!
3822  * \brief Export a mesh to an UNV file
3823  */
3824 //================================================================================
3825
3826 void SMESH_Mesh_i::ExportUNV (const char *file)
3827   throw(SALOME::SALOME_Exception)
3828 {
3829   Unexpect aCatch(SALOME_SalomeException);
3830   if ( _preMeshInfo )
3831     _preMeshInfo->FullLoadFromFile();
3832
3833   // Update Python script
3834   // check names of groups
3835   checkGroupNames();
3836   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportUNV( r'" << file << "' )";
3837
3838   // Perform Export
3839   PrepareForWriting(file);
3840   _impl->ExportUNV(file);
3841 }
3842
3843 //================================================================================
3844 /*!
3845  * \brief Export a mesh to an STL file
3846  */
3847 //================================================================================
3848
3849 void SMESH_Mesh_i::ExportSTL (const char *file, const bool isascii)
3850   throw(SALOME::SALOME_Exception)
3851 {
3852   Unexpect aCatch(SALOME_SalomeException);
3853   if ( _preMeshInfo )
3854     _preMeshInfo->FullLoadFromFile();
3855
3856   // Update Python script
3857   // check names of groups
3858   checkGroupNames();
3859   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
3860                 << ".ExportSTL( r'" << file << "', " << isascii << " )";
3861
3862   CORBA::String_var name;
3863   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( _this() );
3864   if ( !so->_is_nil() )
3865     name = so->GetName();
3866
3867   // Perform Export
3868   PrepareForWriting( file );
3869   _impl->ExportSTL( file, isascii, name.in() );
3870 }
3871
3872 //================================================================================
3873 /*!
3874  * \brief Export a part of mesh to a med file
3875  */
3876 //================================================================================
3877
3878 void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
3879                                    const char*               file,
3880                                    CORBA::Boolean            auto_groups,
3881                                    CORBA::Long               version,
3882                                    CORBA::Boolean            overwrite,
3883                                    CORBA::Boolean            autoDimension,
3884                                    const GEOM::ListOfFields& fields,
3885                                    const char*               geomAssocFields,
3886                                    CORBA::Double             ZTolerance)
3887   throw (SALOME::SALOME_Exception)
3888 {
3889   MESSAGE("MED version: "<< version);
3890   SMESH_TRY;
3891   if ( _preMeshInfo )
3892     _preMeshInfo->FullLoadFromFile();
3893
3894   // check fields
3895   bool have0dField = false;
3896   if ( fields.length() > 0 )
3897   {
3898     GEOM::GEOM_Object_var shapeToMesh = GetShapeToMesh();
3899     if ( shapeToMesh->_is_nil() )
3900       THROW_SALOME_CORBA_EXCEPTION( "No shape to mesh", SALOME::INTERNAL_ERROR );
3901
3902     for ( size_t i = 0; i < fields.length(); ++i )
3903     {
3904       if ( fields[i]->GetDataType() == GEOM::FDT_String )
3905         THROW_SALOME_CORBA_EXCEPTION
3906           ( "Export of string fields is not supported", SALOME::BAD_PARAM);
3907       GEOM::GEOM_Object_var fieldShape = fields[i]->GetShape();
3908       if ( fieldShape->_is_nil() )
3909         THROW_SALOME_CORBA_EXCEPTION( "Null shape under a field", SALOME::INTERNAL_ERROR );
3910       if ( !fieldShape->IsSame( shapeToMesh ) )
3911         THROW_SALOME_CORBA_EXCEPTION
3912           ( "Field defined not on shape", SALOME::BAD_PARAM);
3913       if ( fields[i]->GetDimension() == 0 )
3914         have0dField = true;
3915     }
3916     if ( geomAssocFields )
3917       for ( int i = 0; geomAssocFields[i]; ++i )
3918         switch ( geomAssocFields[i] ) {
3919         case 'v':case 'e':case 'f':case 's': break;
3920         case 'V':case 'E':case 'F':case 'S': break;
3921         default: THROW_SALOME_CORBA_EXCEPTION
3922             ( "geomAssocFields can include only [vefs] characters", SALOME::BAD_PARAM);
3923         }
3924   }
3925
3926   SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
3927
3928   // write mesh
3929
3930   string aMeshName = "Mesh";
3931   SMESHUtils::Deleter< SMESH_MeshPartDS > tmpDSDeleter(0);
3932   if ( CORBA::is_nil( meshPart ) ||
3933        SMESH::DownCast< SMESH_Mesh_i* >( meshPart ))
3934   {
3935     aMeshName = prepareMeshNameAndGroups(file, overwrite);
3936     _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version,
3937                       0, autoDimension, /*addODOnVertices=*/have0dField,
3938                       ZTolerance);
3939     meshDS = _impl->GetMeshDS();
3940   }
3941   else
3942   {
3943     if ( _preMeshInfo )
3944       _preMeshInfo->FullLoadFromFile();
3945
3946     PrepareForWriting(file, overwrite);
3947
3948     SALOMEDS::SObject_wrap SO = _gen_i->ObjectToSObject( meshPart );
3949     if ( !SO->_is_nil() ) {
3950       CORBA::String_var name = SO->GetName();
3951       aMeshName = name;
3952     }
3953
3954     SMESH_MeshPartDS* partDS = new SMESH_MeshPartDS( meshPart );
3955     _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version,
3956                       partDS, autoDimension, /*addODOnVertices=*/have0dField, ZTolerance);
3957     meshDS = tmpDSDeleter._obj = partDS;
3958   }
3959
3960   // write fields
3961
3962   if ( _impl->HasShapeToMesh() )
3963   {
3964     DriverMED_W_Field fieldWriter;
3965     fieldWriter.SetFile( file );
3966     fieldWriter.SetMeshName( aMeshName );
3967     fieldWriter.AddODOnVertices( have0dField );
3968
3969     exportMEDFields( fieldWriter, meshDS, fields, geomAssocFields );
3970   }
3971
3972   // dump
3973   GEOM::ListOfGBO_var goList = new GEOM::ListOfGBO;
3974   goList->length( fields.length() );
3975   for ( size_t i = 0; i < fields.length(); ++i )
3976   {
3977     GEOM::GEOM_BaseObject_var gbo = GEOM::GEOM_BaseObject::_narrow( fields[i] );
3978     goList[i] = gbo;
3979   }
3980   TPythonDump() << _this() << ".ExportPartToMED( "
3981                 << meshPart << ", r'"
3982                 << file << "', "
3983                 << auto_groups << ", "
3984                 << version << ", "
3985                 << overwrite << ", "
3986                 << autoDimension << ", "
3987                 << goList << ", '"
3988                 << ( geomAssocFields ? geomAssocFields : "" ) << "',"
3989                 << TVar( ZTolerance )
3990                 << " )";
3991
3992   SMESH_CATCH( SMESH::throwCorbaException );
3993 }
3994
3995 //================================================================================
3996 /*!
3997  * Write GEOM fields to MED file
3998  */
3999 //================================================================================
4000
4001 void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
4002                                     SMESHDS_Mesh*             meshDS,
4003                                     const GEOM::ListOfFields& fields,
4004                                     const char*               geomAssocFields)
4005 {
4006 #define METH "SMESH_Mesh_i::exportMEDFields() "
4007
4008   if (( fields.length() < 1 ) &&
4009       ( !geomAssocFields || !geomAssocFields[0] ))
4010     return;
4011
4012   std::vector< std::vector< double > > dblVals;
4013   std::vector< std::vector< int > >    intVals;
4014   std::vector< int >                   subIdsByDim[ 4 ];
4015   const double noneDblValue = 0.;
4016   const double noneIntValue = 0;
4017
4018   for ( size_t iF = 0; iF < fields.length(); ++iF )
4019   {
4020     // set field data
4021
4022     int dim = fields[ iF ]->GetDimension();
4023     SMDSAbs_ElementType elemType;
4024     TopAbs_ShapeEnum    shapeType;
4025     switch ( dim ) {
4026     case 0: elemType = SMDSAbs_0DElement; shapeType = TopAbs_VERTEX; break;
4027     case 1: elemType = SMDSAbs_Edge;      shapeType = TopAbs_EDGE;   break;
4028     case 2: elemType = SMDSAbs_Face;      shapeType = TopAbs_FACE;   break;
4029     case 3: elemType = SMDSAbs_Volume;    shapeType = TopAbs_SOLID;  break;
4030     default:
4031       continue; // skip fields on whole shape
4032     }
4033     GEOM::field_data_type dataType = fields[ iF ]->GetDataType();
4034     if ( dataType == GEOM::FDT_String )
4035       continue;
4036     GEOM::ListOfLong_var stepIDs = fields[ iF ]->GetSteps();
4037     if ( stepIDs->length() < 1 )
4038       continue;
4039     GEOM::string_array_var comps = fields[ iF ]->GetComponents();
4040     if ( comps->length() < 1 )
4041       continue;
4042     CORBA::String_var       name = fields[ iF ]->GetName();
4043
4044     if ( !fieldWriter.Set( meshDS,
4045                            name.in(),
4046                            elemType,
4047                            comps->length(),
4048                            /*isIntData=*/false ))//( dataType == GEOM::FDT_Int )))
4049       continue;
4050
4051     for ( size_t iC = 0; iC < comps->length(); ++iC )
4052       fieldWriter.SetCompName( iC, comps[ iC ].in() );
4053
4054     dblVals.resize( comps->length() );
4055     intVals.resize( comps->length() );
4056
4057     // find sub-shape IDs
4058
4059     std::vector< int >& subIds = subIdsByDim[ dim ];
4060     if ( subIds.empty() )
4061       for ( int id = 1; id <= meshDS->MaxShapeIndex(); ++id )
4062         if ( meshDS->IndexToShape( id ).ShapeType() == shapeType )
4063           subIds.push_back( id );
4064
4065     // write steps
4066
4067     SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
4068     if ( !elemIt )
4069       continue;
4070
4071     for ( size_t iS = 0; iS < stepIDs->length(); ++iS )
4072     {
4073       GEOM::GEOM_FieldStep_var step = fields[ iF ]->GetStep( stepIDs[ iS ]);
4074       if ( step->_is_nil() )
4075         continue;
4076
4077       CORBA::Long stamp = step->GetStamp();
4078       CORBA::Long id    = step->GetID();
4079       fieldWriter.SetDtIt( int( stamp ), int( id ));
4080
4081       // fill dblVals or intVals
4082       for ( size_t iC = 0; iC < comps->length(); ++iC )
4083         if ( dataType == GEOM::FDT_Double )
4084         {
4085           dblVals[ iC ].clear();
4086           dblVals[ iC ].resize( meshDS->MaxShapeIndex()+1, 0 );
4087         }
4088         else
4089         {
4090           intVals[ iC ].clear();
4091           intVals[ iC ].resize( meshDS->MaxShapeIndex()+1, 0 );
4092         }
4093       switch ( dataType )
4094       {
4095       case GEOM::FDT_Double:
4096       {
4097         GEOM::GEOM_DoubleFieldStep_var dblStep = GEOM::GEOM_DoubleFieldStep::_narrow( step );
4098         if ( dblStep->_is_nil() ) continue;
4099         GEOM::ListOfDouble_var vv = dblStep->GetValues();
4100         if ( vv->length() != subIds.size() * comps->length() )
4101           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
4102         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
4103           for ( size_t iC = 0; iC < comps->length(); ++iC )
4104             dblVals[ iC ][ subIds[ iS ]] = vv[ iV++ ];
4105         break;
4106       }
4107       case GEOM::FDT_Int:
4108       {
4109         GEOM::GEOM_IntFieldStep_var intStep = GEOM::GEOM_IntFieldStep::_narrow( step );
4110         if ( intStep->_is_nil() ) continue;
4111         GEOM::ListOfLong_var vv = intStep->GetValues();
4112         if ( vv->length() != subIds.size() * comps->length() )
4113           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
4114         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
4115           for ( size_t iC = 0; iC < comps->length(); ++iC )
4116             intVals[ iC ][ subIds[ iS ]] = (int) vv[ iV++ ];
4117         break;
4118       }
4119       case GEOM::FDT_Bool:
4120       {
4121         GEOM::GEOM_BoolFieldStep_var boolStep = GEOM::GEOM_BoolFieldStep::_narrow( step );
4122         if ( boolStep->_is_nil() ) continue;
4123         GEOM::short_array_var vv = boolStep->GetValues();
4124         if ( vv->length() != subIds.size() * comps->length() )
4125           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
4126         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
4127           for ( size_t iC = 0; iC < comps->length(); ++iC )
4128             intVals[ iC ][ subIds[ iS ]] = (int) vv[ iV++ ];
4129         break;
4130       }
4131       default: continue;
4132       }
4133
4134       // pass values to fieldWriter
4135       elemIt = fieldWriter.GetOrderedElems();
4136       if ( dataType == GEOM::FDT_Double )
4137         while ( elemIt->more() )
4138         {
4139           const SMDS_MeshElement* e = elemIt->next();
4140           const int shapeID = e->getshapeId();
4141           if ( shapeID < 1 || shapeID >= (int) dblVals[0].size() )
4142             for ( size_t iC = 0; iC < comps->length(); ++iC )
4143               fieldWriter.AddValue( noneDblValue );
4144           else
4145             for ( size_t iC = 0; iC < comps->length(); ++iC )
4146               fieldWriter.AddValue( dblVals[ iC ][ shapeID ]);
4147         }
4148       else
4149         while ( elemIt->more() )
4150         {
4151           const SMDS_MeshElement* e = elemIt->next();
4152           const int shapeID = e->getshapeId();
4153           if ( shapeID < 1 || shapeID >= (int) intVals[0].size() )
4154             for ( size_t iC = 0; iC < comps->length(); ++iC )
4155               fieldWriter.AddValue( (double) noneIntValue );
4156           else
4157             for ( size_t iC = 0; iC < comps->length(); ++iC )
4158               fieldWriter.AddValue( (double) intVals[ iC ][ shapeID ]);
4159         }
4160
4161       // write a step
4162       fieldWriter.Perform();
4163       SMESH_ComputeErrorPtr res = fieldWriter.GetError();
4164       if ( res && res->IsKO() )
4165       {
4166         if ( res->myComment.empty() )
4167         { THROW_SALOME_CORBA_EXCEPTION( METH "Fatal error", SALOME::INTERNAL_ERROR ); }
4168         else
4169         { THROW_SALOME_CORBA_EXCEPTION( res->myComment.c_str(), SALOME::INTERNAL_ERROR ); }
4170       }
4171
4172     } // loop on steps
4173   } // loop on fields
4174
4175   if ( !geomAssocFields || !geomAssocFields[0] )
4176     return;
4177
4178   // write geomAssocFields
4179
4180   std::vector< int > shapeDim( TopAbs_SHAPE + 1 );
4181   shapeDim[ TopAbs_COMPOUND  ] = 3;
4182   shapeDim[ TopAbs_COMPSOLID ] = 3;
4183   shapeDim[ TopAbs_SOLID     ] = 3;
4184   shapeDim[ TopAbs_SHELL     ] = 2;
4185   shapeDim[ TopAbs_FACE      ] = 2;
4186   shapeDim[ TopAbs_WIRE      ] = 1;
4187   shapeDim[ TopAbs_EDGE      ] = 1;
4188   shapeDim[ TopAbs_VERTEX    ] = 0;
4189   shapeDim[ TopAbs_SHAPE     ] = 3;
4190
4191   for ( int iF = 0; geomAssocFields[ iF ]; ++iF )
4192   {
4193     std::vector< std::string > compNames;
4194     switch ( geomAssocFields[ iF ]) {
4195     case 'v': case 'V':
4196       fieldWriter.Set( meshDS, "_vertices_", SMDSAbs_Node, /*nbComps=*/2, /*isInt=*/false );
4197       compNames.push_back( "dim" );
4198       break;
4199     case 'e': case 'E':
4200       fieldWriter.Set( meshDS, "_edges_", SMDSAbs_Edge, /*nbComps=*/1, /*isInt=*/false );
4201       break;
4202     case 'f': case 'F':
4203       fieldWriter.Set( meshDS, "_faces_", SMDSAbs_Face, /*nbComps=*/1, /*isInt=*/false );
4204       break;
4205     case 's': case 'S':
4206       fieldWriter.Set( meshDS, "_solids_", SMDSAbs_Volume, /*nbComps=*/1, /*isInt=*/false );
4207       break;
4208     default: continue;
4209     }
4210     compNames.push_back( "id" );
4211     for ( size_t iC = 0; iC < compNames.size(); ++iC )
4212       fieldWriter.SetCompName( iC, compNames[ iC ].c_str() );
4213
4214     fieldWriter.SetDtIt( -1, -1 );
4215
4216     SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
4217     if ( !elemIt )
4218       continue;
4219
4220     if ( compNames.size() == 2 ) // _vertices_
4221       while ( elemIt->more() )
4222       {
4223         const SMDS_MeshElement* e = elemIt->next();
4224         const int shapeID = e->getshapeId();
4225         if ( shapeID < 1 )
4226         {
4227           fieldWriter.AddValue( (double) -1 );
4228           fieldWriter.AddValue( (double) -1 );
4229         }
4230         else
4231         {
4232           const TopoDS_Shape& S = meshDS->IndexToShape( shapeID );
4233           fieldWriter.AddValue( (double) ( S.IsNull() ? -1 : shapeDim[ S.ShapeType() ]));
4234           fieldWriter.AddValue( (double) shapeID );
4235         }
4236       }
4237     else
4238       while ( elemIt->more() )
4239       {
4240         const SMDS_MeshElement* e = elemIt->next();
4241         const int shapeID = e->getshapeId();
4242         if ( shapeID < 1 )
4243           fieldWriter.AddValue( (double) -1 );
4244         else
4245           fieldWriter.AddValue( (double) shapeID );
4246       }
4247
4248     // write a step
4249     fieldWriter.Perform();
4250     SMESH_ComputeErrorPtr res = fieldWriter.GetError();
4251     if ( res && res->IsKO() )
4252     {
4253       if ( res->myComment.empty() )
4254       { THROW_SALOME_CORBA_EXCEPTION( METH "Fatal error", SALOME::INTERNAL_ERROR ); }
4255       else
4256       { THROW_SALOME_CORBA_EXCEPTION( res->myComment.c_str(), SALOME::INTERNAL_ERROR ); }
4257     }
4258
4259   } // loop on geomAssocFields
4260
4261 #undef METH
4262 }
4263
4264 //================================================================================
4265 /*!
4266  * \brief Export a part of mesh to a DAT file
4267  */
4268 //================================================================================
4269
4270 void SMESH_Mesh_i::ExportPartToDAT(::SMESH::SMESH_IDSource_ptr meshPart,
4271                                    const char*                 file)
4272   throw (SALOME::SALOME_Exception)
4273 {
4274   Unexpect aCatch(SALOME_SalomeException);
4275   if ( _preMeshInfo )
4276     _preMeshInfo->FullLoadFromFile();
4277
4278   PrepareForWriting(file);
4279
4280   SMESH_MeshPartDS partDS( meshPart );
4281   _impl->ExportDAT(file,&partDS);
4282
4283   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
4284                 << ".ExportPartToDAT( " << meshPart << ", r'" << file << "' )";
4285 }
4286 //================================================================================
4287 /*!
4288  * \brief Export a part of mesh to an UNV file
4289  */
4290 //================================================================================
4291
4292 void SMESH_Mesh_i::ExportPartToUNV(::SMESH::SMESH_IDSource_ptr meshPart,
4293                                    const char*                 file)
4294   throw (SALOME::SALOME_Exception)
4295 {
4296   Unexpect aCatch(SALOME_SalomeException);
4297   if ( _preMeshInfo )
4298     _preMeshInfo->FullLoadFromFile();
4299
4300   PrepareForWriting(file);
4301
4302   SMESH_MeshPartDS partDS( meshPart );
4303   _impl->ExportUNV(file, &partDS);
4304
4305   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
4306                 << ".ExportPartToUNV( " << meshPart<< ", r'" << file << "' )";
4307 }
4308 //================================================================================
4309 /*!
4310  * \brief Export a part of mesh to an STL file
4311  */
4312 //================================================================================
4313
4314 void SMESH_Mesh_i::ExportPartToSTL(::SMESH::SMESH_IDSource_ptr meshPart,
4315                                    const char*                 file,
4316                                    ::CORBA::Boolean            isascii)
4317   throw (SALOME::SALOME_Exception)
4318 {
4319   Unexpect aCatch(SALOME_SalomeException);
4320   if ( _preMeshInfo )
4321     _preMeshInfo->FullLoadFromFile();
4322
4323   PrepareForWriting(file);
4324
4325   CORBA::String_var name;
4326   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( meshPart );
4327   if ( !so->_is_nil() )
4328     name = so->GetName();
4329
4330   SMESH_MeshPartDS partDS( meshPart );
4331   _impl->ExportSTL( file, isascii, name.in(), &partDS );
4332
4333   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportPartToSTL( "
4334                 << meshPart<< ", r'" << file << "', " << isascii << ")";
4335 }
4336
4337 //================================================================================
4338 /*!
4339  * \brief Export a part of mesh to an STL file
4340  */
4341 //================================================================================
4342
4343 void SMESH_Mesh_i::ExportCGNS(::SMESH::SMESH_IDSource_ptr meshPart,
4344                               const char*                 file,
4345                               CORBA::Boolean              overwrite,
4346                               CORBA::Boolean              groupElemsByType)
4347   throw (SALOME::SALOME_Exception)
4348 {
4349 #ifdef WITH_CGNS
4350   Unexpect aCatch(SALOME_SalomeException);
4351   if ( _preMeshInfo )
4352     _preMeshInfo->FullLoadFromFile();
4353
4354   PrepareForWriting(file,overwrite);
4355
4356   std::string meshName("");
4357   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( meshPart );
4358   if ( !so->_is_nil() )
4359   {
4360     CORBA::String_var name = so->GetName();
4361     meshName = name.in();
4362   }
4363   SMESH_TRY;
4364
4365   SMESH_MeshPartDS partDS( meshPart );
4366   _impl->ExportCGNS(file, &partDS, meshName.c_str(), groupElemsByType );
4367
4368   SMESH_CATCH( SMESH::throwCorbaException );
4369
4370   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportCGNS( "
4371                 << meshPart<< ", r'" << file << "', " << overwrite << ")";
4372 #else
4373   THROW_SALOME_CORBA_EXCEPTION("CGNS library is unavailable", SALOME::INTERNAL_ERROR);
4374 #endif
4375 }
4376
4377 //================================================================================
4378 /*!
4379  * \brief Export a part of mesh to a GMF file
4380  */
4381 //================================================================================
4382
4383 void SMESH_Mesh_i::ExportGMF(::SMESH::SMESH_IDSource_ptr meshPart,
4384                              const char*                 file,
4385                              bool                        withRequiredGroups)
4386   throw (SALOME::SALOME_Exception)
4387 {
4388   Unexpect aCatch(SALOME_SalomeException);
4389   if ( _preMeshInfo )
4390     _preMeshInfo->FullLoadFromFile();
4391
4392   PrepareForWriting(file,/*overwrite=*/true);
4393
4394   SMESH_MeshPartDS partDS( meshPart );
4395   _impl->ExportGMF(file, &partDS, withRequiredGroups);
4396
4397   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportGMF( "
4398                 << meshPart<< ", r'"
4399                 << file << "', "
4400                 << withRequiredGroups << ")";
4401 }
4402
4403 //=============================================================================
4404 /*!
4405  * Return computation progress [0.,1]
4406  */
4407 //=============================================================================
4408
4409 CORBA::Double SMESH_Mesh_i::GetComputeProgress()
4410 {
4411   SMESH_TRY;
4412
4413   return _impl->GetComputeProgress();
4414
4415   SMESH_CATCH( SMESH::doNothing );
4416   return 0.;
4417 }
4418
4419 //================================================================================
4420 /*!
4421  * \brief Return nb of nodes
4422  */
4423 //================================================================================
4424
4425 CORBA::Long SMESH_Mesh_i::NbNodes()throw(SALOME::SALOME_Exception)
4426 {
4427   Unexpect aCatch(SALOME_SalomeException);
4428   if ( _preMeshInfo )
4429     return _preMeshInfo->NbNodes();
4430
4431   return _impl->NbNodes();
4432 }
4433
4434 //================================================================================
4435 /*!
4436  * \brief Return nb of elements
4437  */
4438 //================================================================================
4439
4440 CORBA::Long SMESH_Mesh_i::NbElements()throw (SALOME::SALOME_Exception)
4441 {
4442   Unexpect aCatch(SALOME_SalomeException);
4443   if ( _preMeshInfo )
4444     return _preMeshInfo->NbElements();
4445
4446   return Nb0DElements() + NbEdges() + NbFaces() + NbVolumes() + NbBalls();
4447 }
4448
4449 //================================================================================
4450 /*!
4451  * \brief Return nb of 0D elements
4452  */
4453 //================================================================================
4454
4455 CORBA::Long SMESH_Mesh_i::Nb0DElements()throw (SALOME::SALOME_Exception)
4456 {
4457   Unexpect aCatch(SALOME_SalomeException);
4458   if ( _preMeshInfo )
4459     return _preMeshInfo->Nb0DElements();
4460
4461   return _impl->Nb0DElements();
4462 }
4463
4464 //================================================================================
4465 /*!
4466  * \brief Return nb of BALL elements
4467  */
4468 //================================================================================
4469
4470 CORBA::Long SMESH_Mesh_i::NbBalls() throw (SALOME::SALOME_Exception)
4471 {
4472   Unexpect aCatch(SALOME_SalomeException);
4473   if ( _preMeshInfo )
4474     return _preMeshInfo->NbBalls();
4475
4476   return _impl->NbBalls();
4477 }
4478
4479 //================================================================================
4480 /*!
4481  * \brief Return nb of 1D elements
4482  */
4483 //================================================================================
4484
4485 CORBA::Long SMESH_Mesh_i::NbEdges()throw(SALOME::SALOME_Exception)
4486 {
4487   Unexpect aCatch(SALOME_SalomeException);
4488   if ( _preMeshInfo )
4489     return _preMeshInfo->NbEdges();
4490
4491   return _impl->NbEdges();
4492 }
4493
4494 //================================================================================
4495 /*!
4496  * \brief Return nb of edges
4497  */
4498 //================================================================================
4499
4500 CORBA::Long SMESH_Mesh_i::NbEdgesOfOrder(SMESH::ElementOrder order)
4501   throw(SALOME::SALOME_Exception)
4502 {
4503   Unexpect aCatch(SALOME_SalomeException);
4504   if ( _preMeshInfo )
4505     return _preMeshInfo->NbEdges( (SMDSAbs_ElementOrder) order );
4506
4507   return _impl->NbEdges( (SMDSAbs_ElementOrder) order);
4508 }
4509
4510 //================================================================================
4511 /*!
4512  * \brief Return nb of faces
4513  */
4514 //================================================================================
4515
4516 CORBA::Long SMESH_Mesh_i::NbFaces()throw(SALOME::SALOME_Exception)
4517 {
4518   Unexpect aCatch(SALOME_SalomeException);
4519   if ( _preMeshInfo )
4520     return _preMeshInfo->NbFaces();
4521
4522   return _impl->NbFaces();
4523 }
4524
4525 //================================================================================
4526 /*!
4527  * \brief Return nb of tringles
4528  */
4529 //================================================================================
4530
4531 CORBA::Long SMESH_Mesh_i::NbTriangles()throw(SALOME::SALOME_Exception)
4532 {
4533   Unexpect aCatch(SALOME_SalomeException);
4534   if ( _preMeshInfo )
4535     return _preMeshInfo->NbTriangles();
4536
4537   return _impl->NbTriangles();
4538 }
4539
4540 //================================================================================
4541 /*!
4542  * \brief Return nb of bi-quadratic triangles
4543  */
4544 //================================================================================
4545
4546 CORBA::Long SMESH_Mesh_i::NbBiQuadTriangles()throw(SALOME::SALOME_Exception)
4547 {
4548   Unexpect aCatch(SALOME_SalomeException);
4549   if ( _preMeshInfo )
4550     return _preMeshInfo->NbBiQuadTriangles();
4551
4552   return _impl->NbBiQuadTriangles();
4553 }
4554
4555 CORBA::Long SMESH_Mesh_i::NbQuadrangles()throw(SALOME::SALOME_Exception)
4556 {
4557   Unexpect aCatch(SALOME_SalomeException);
4558   if ( _preMeshInfo )
4559     return _preMeshInfo->NbQuadrangles();
4560
4561   return _impl->NbQuadrangles();
4562 }
4563
4564 CORBA::Long SMESH_Mesh_i::NbBiQuadQuadrangles()throw(SALOME::SALOME_Exception)
4565 {
4566   Unexpect aCatch(SALOME_SalomeException);
4567   if ( _preMeshInfo )
4568     return _preMeshInfo->NbBiQuadQuadrangles();
4569
4570   return _impl->NbBiQuadQuadrangles();
4571 }
4572
4573 CORBA::Long SMESH_Mesh_i::NbPolygons() throw(SALOME::SALOME_Exception)
4574 {
4575   Unexpect aCatch(SALOME_SalomeException);
4576   if ( _preMeshInfo )
4577     return _preMeshInfo->NbPolygons();
4578
4579   return _impl->NbPolygons();
4580 }
4581
4582 CORBA::Long SMESH_Mesh_i::NbPolygonsOfOrder(SMESH::ElementOrder order) throw(SALOME::SALOME_Exception)
4583 {
4584   Unexpect aCatch(SALOME_SalomeException);
4585   if ( _preMeshInfo )
4586     return _preMeshInfo->NbPolygons((SMDSAbs_ElementOrder) order);
4587
4588   return _impl->NbPolygons((SMDSAbs_ElementOrder)order);
4589 }
4590
4591 CORBA::Long SMESH_Mesh_i::NbFacesOfOrder(SMESH::ElementOrder order)
4592   throw(SALOME::SALOME_Exception)
4593 {
4594   Unexpect aCatch(SALOME_SalomeException);
4595   if ( _preMeshInfo )
4596     return _preMeshInfo->NbFaces( (SMDSAbs_ElementOrder) order );
4597
4598   return _impl->NbFaces( (SMDSAbs_ElementOrder) order);
4599 }
4600
4601 CORBA::Long SMESH_Mesh_i::NbTrianglesOfOrder(SMESH::ElementOrder order)
4602   throw(SALOME::SALOME_Exception)
4603 {
4604   Unexpect aCatch(SALOME_SalomeException);
4605   if ( _preMeshInfo )
4606     return _preMeshInfo->NbTriangles( (SMDSAbs_ElementOrder) order );
4607
4608   return _impl->NbTriangles( (SMDSAbs_ElementOrder) order);
4609 }
4610
4611 CORBA::Long SMESH_Mesh_i::NbQuadranglesOfOrder(SMESH::ElementOrder order)
4612   throw(SALOME::SALOME_Exception)
4613 {
4614   Unexpect aCatch(SALOME_SalomeException);
4615   if ( _preMeshInfo )
4616     return _preMeshInfo->NbQuadrangles( (SMDSAbs_ElementOrder) order );
4617
4618   return _impl->NbQuadrangles( (SMDSAbs_ElementOrder) order);
4619 }
4620
4621 //=============================================================================
4622
4623 CORBA::Long SMESH_Mesh_i::NbVolumes()throw(SALOME::SALOME_Exception)
4624 {
4625   Unexpect aCatch(SALOME_SalomeException);
4626   if ( _preMeshInfo )
4627     return _preMeshInfo->NbVolumes();
4628
4629   return _impl->NbVolumes();
4630 }
4631
4632 CORBA::Long SMESH_Mesh_i::NbTetras()throw(SALOME::SALOME_Exception)
4633 {
4634   Unexpect aCatch(SALOME_SalomeException);
4635   if ( _preMeshInfo )
4636     return _preMeshInfo->NbTetras();
4637
4638   return _impl->NbTetras();
4639 }
4640
4641 CORBA::Long SMESH_Mesh_i::NbHexas()throw(SALOME::SALOME_Exception)
4642 {
4643   Unexpect aCatch(SALOME_SalomeException);
4644   if ( _preMeshInfo )
4645     return _preMeshInfo->NbHexas();
4646
4647   return _impl->NbHexas();
4648 }
4649
4650 CORBA::Long SMESH_Mesh_i::NbTriQuadraticHexas()throw(SALOME::SALOME_Exception)
4651 {
4652   Unexpect aCatch(SALOME_SalomeException);
4653   if ( _preMeshInfo )
4654     return _preMeshInfo->NbTriQuadHexas();
4655
4656   return _impl->NbTriQuadraticHexas();
4657 }
4658
4659 CORBA::Long SMESH_Mesh_i::NbPyramids()throw(SALOME::SALOME_Exception)
4660 {
4661   Unexpect aCatch(SALOME_SalomeException);
4662   if ( _preMeshInfo )
4663     return _preMeshInfo->NbPyramids();
4664
4665   return _impl->NbPyramids();
4666 }
4667
4668 CORBA::Long SMESH_Mesh_i::NbPrisms()throw(SALOME::SALOME_Exception)
4669 {
4670   Unexpect aCatch(SALOME_SalomeException);
4671   if ( _preMeshInfo )
4672     return _preMeshInfo->NbPrisms();
4673
4674   return _impl->NbPrisms();
4675 }
4676
4677 CORBA::Long SMESH_Mesh_i::NbHexagonalPrisms()throw(SALOME::SALOME_Exception)
4678 {
4679   Unexpect aCatch(SALOME_SalomeException);
4680   if ( _preMeshInfo )
4681     return _preMeshInfo->NbHexPrisms();
4682
4683   return _impl->NbHexagonalPrisms();
4684 }
4685
4686 CORBA::Long SMESH_Mesh_i::NbPolyhedrons()throw(SALOME::SALOME_Exception)
4687 {
4688   Unexpect aCatch(SALOME_SalomeException);
4689   if ( _preMeshInfo )
4690     return _preMeshInfo->NbPolyhedrons();
4691
4692   return _impl->NbPolyhedrons();
4693 }
4694
4695 CORBA::Long SMESH_Mesh_i::NbVolumesOfOrder(SMESH::ElementOrder order)
4696   throw(SALOME::SALOME_Exception)
4697 {
4698   Unexpect aCatch(SALOME_SalomeException);
4699   if ( _preMeshInfo )
4700     return _preMeshInfo->NbVolumes( (SMDSAbs_ElementOrder) order );
4701
4702   return _impl->NbVolumes( (SMDSAbs_ElementOrder) order);
4703 }
4704
4705 CORBA::Long SMESH_Mesh_i::NbTetrasOfOrder(SMESH::ElementOrder order)
4706   throw(SALOME::SALOME_Exception)
4707 {
4708   Unexpect aCatch(SALOME_SalomeException);
4709   if ( _preMeshInfo )
4710     return _preMeshInfo->NbTetras( (SMDSAbs_ElementOrder) order);
4711
4712   return _impl->NbTetras( (SMDSAbs_ElementOrder) order);
4713 }
4714
4715 CORBA::Long SMESH_Mesh_i::NbHexasOfOrder(SMESH::ElementOrder order)
4716   throw(SALOME::SALOME_Exception)
4717 {
4718   Unexpect aCatch(SALOME_SalomeException);
4719   if ( _preMeshInfo )
4720     return _preMeshInfo->NbHexas( (SMDSAbs_ElementOrder) order);
4721
4722   return _impl->NbHexas( (SMDSAbs_ElementOrder) order);
4723 }
4724
4725 CORBA::Long SMESH_Mesh_i::NbPyramidsOfOrder(SMESH::ElementOrder order)
4726   throw(SALOME::SALOME_Exception)
4727 {
4728   Unexpect aCatch(SALOME_SalomeException);
4729   if ( _preMeshInfo )
4730     return _preMeshInfo->NbPyramids( (SMDSAbs_ElementOrder) order);
4731
4732   return _impl->NbPyramids( (SMDSAbs_ElementOrder) order);
4733 }
4734
4735 CORBA::Long SMESH_Mesh_i::NbPrismsOfOrder(SMESH::ElementOrder order)
4736   throw(SALOME::SALOME_Exception)
4737 {
4738   Unexpect aCatch(SALOME_SalomeException);
4739   if ( _preMeshInfo )
4740     return _preMeshInfo->NbPrisms( (SMDSAbs_ElementOrder) order);
4741
4742   return _impl->NbPrisms( (SMDSAbs_ElementOrder) order);
4743 }
4744
4745 //=============================================================================
4746 /*!
4747  * Return nb of published sub-meshes
4748  */
4749 //=============================================================================
4750
4751 CORBA::Long SMESH_Mesh_i::NbSubMesh()throw(SALOME::SALOME_Exception)
4752 {
4753   Unexpect aCatch(SALOME_SalomeException);
4754   return _mapSubMesh_i.size();
4755 }
4756
4757 //=============================================================================
4758 /*!
4759  * Dumps mesh into a string
4760  */
4761 //=============================================================================
4762
4763 char* SMESH_Mesh_i::Dump()
4764 {
4765   ostringstream os;
4766   _impl->Dump( os );
4767   return CORBA::string_dup( os.str().c_str() );
4768 }
4769
4770 //=============================================================================
4771 /*!
4772  * Method of SMESH_IDSource interface
4773  */
4774 //=============================================================================
4775
4776 SMESH::long_array* SMESH_Mesh_i::GetIDs()
4777 {
4778   return GetElementsId();
4779 }
4780
4781 //=============================================================================
4782 /*!
4783  * Return ids of all elements
4784  */
4785 //=============================================================================
4786
4787 SMESH::long_array* SMESH_Mesh_i::GetElementsId()
4788   throw (SALOME::SALOME_Exception)
4789 {
4790   Unexpect aCatch(SALOME_SalomeException);
4791   if ( _preMeshInfo )
4792     _preMeshInfo->FullLoadFromFile();
4793
4794   SMESH::long_array_var aResult = new SMESH::long_array();
4795   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
4796
4797   if ( aSMESHDS_Mesh == NULL )
4798     return aResult._retn();
4799
4800   long nbElements = NbElements();
4801   aResult->length( nbElements );
4802   SMDS_ElemIteratorPtr anIt = aSMESHDS_Mesh->elementsIterator();
4803   for ( int i = 0, n = nbElements; i < n && anIt->more(); i++ )
4804     aResult[i] = anIt->next()->GetID();
4805
4806   return aResult._retn();
4807 }
4808
4809
4810 //=============================================================================
4811 /*!
4812  * Return ids of all elements of given type
4813  */
4814 //=============================================================================
4815
4816 SMESH::long_array* SMESH_Mesh_i::GetElementsByType( SMESH::ElementType theElemType )
4817     throw (SALOME::SALOME_Exception)
4818 {
4819   Unexpect aCatch(SALOME_SalomeException);
4820   if ( _preMeshInfo )
4821     _preMeshInfo->FullLoadFromFile();
4822
4823   SMESH::long_array_var aResult = new SMESH::long_array();
4824   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
4825
4826   if ( aSMESHDS_Mesh == NULL )
4827     return aResult._retn();
4828
4829   long nbElements = NbElements();
4830
4831   // No sense in returning ids of elements along with ids of nodes:
4832   // when theElemType == SMESH::ALL, return node ids only if
4833   // there are no elements
4834   if ( theElemType == SMESH::NODE || (theElemType == SMESH::ALL && nbElements == 0) )
4835     return GetNodesId();
4836
4837   aResult->length( nbElements );
4838
4839   int i = 0;
4840
4841   SMDS_ElemIteratorPtr anIt = aSMESHDS_Mesh->elementsIterator( (SMDSAbs_ElementType)theElemType );
4842   while ( i < nbElements && anIt->more() )
4843     aResult[i++] = anIt->next()->GetID();
4844
4845   aResult->length( i );
4846
4847   return aResult._retn();
4848 }
4849
4850 //=============================================================================
4851 /*!
4852  * Return ids of all nodes
4853  */
4854 //=============================================================================
4855
4856 SMESH::long_array* SMESH_Mesh_i::GetNodesId()
4857   throw (SALOME::SALOME_Exception)
4858 {
4859   Unexpect aCatch(SALOME_SalomeException);
4860   if ( _preMeshInfo )
4861     _preMeshInfo->FullLoadFromFile();
4862
4863   SMESH::long_array_var aResult = new SMESH::long_array();
4864   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4865
4866   if ( aMeshDS == NULL )
4867     return aResult._retn();
4868
4869   long nbNodes = NbNodes();
4870   aResult->length( nbNodes );
4871   SMDS_NodeIteratorPtr anIt = aMeshDS->nodesIterator();
4872   for ( int i = 0, n = nbNodes; i < n && anIt->more(); i++ )
4873     aResult[i] = anIt->next()->GetID();
4874
4875   return aResult._retn();
4876 }
4877
4878 //=============================================================================
4879 /*!
4880  * Return type of the given element
4881  */
4882 //=============================================================================
4883
4884 SMESH::ElementType SMESH_Mesh_i::GetElementType( const CORBA::Long id, const bool iselem )
4885   throw (SALOME::SALOME_Exception)
4886 {
4887   SMESH::ElementType type = SMESH::ALL;
4888   SMESH_TRY;
4889
4890   if ( _preMeshInfo )
4891     _preMeshInfo->FullLoadFromFile();
4892
4893   type = ( SMESH::ElementType ) _impl->GetElementType( id, iselem );
4894
4895   SMESH_CATCH( SMESH::throwCorbaException );
4896
4897   return type;
4898 }
4899
4900 //=============================================================================
4901 /*!
4902  * Return geometric type of the given element
4903  */
4904 //=============================================================================
4905
4906 SMESH::EntityType SMESH_Mesh_i::GetElementGeomType( const CORBA::Long id )
4907   throw (SALOME::SALOME_Exception)
4908 {
4909   if ( _preMeshInfo )
4910     _preMeshInfo->FullLoadFromFile();
4911
4912   const SMDS_MeshElement* e = _impl->GetMeshDS()->FindElement(id);
4913   if ( !e )
4914     THROW_SALOME_CORBA_EXCEPTION( "invalid element id", SALOME::BAD_PARAM );
4915
4916   return ( SMESH::EntityType ) e->GetEntityType();
4917 }
4918
4919 //=============================================================================
4920 /*!
4921  * Return type of the given element
4922  */
4923 //=============================================================================
4924
4925 SMESH::GeometryType SMESH_Mesh_i::GetElementShape( const CORBA::Long id )
4926   throw (SALOME::SALOME_Exception)
4927 {
4928   if ( _preMeshInfo )
4929     _preMeshInfo->FullLoadFromFile();
4930
4931   const SMDS_MeshElement* e = _impl->GetMeshDS()->FindElement(id);
4932   if ( !e )
4933     THROW_SALOME_CORBA_EXCEPTION( "invalid element id", SALOME::BAD_PARAM );
4934
4935   return ( SMESH::GeometryType ) e->GetGeomType();
4936 }
4937
4938 //=============================================================================
4939 /*!
4940  * Return ID of elements for given submesh
4941  */
4942 //=============================================================================
4943
4944 SMESH::long_array* SMESH_Mesh_i::GetSubMeshElementsId(const CORBA::Long ShapeID)
4945      throw (SALOME::SALOME_Exception)
4946 {
4947   SMESH::long_array_var aResult = new SMESH::long_array();
4948
4949   SMESH_TRY;
4950   if ( _preMeshInfo )
4951     _preMeshInfo->FullLoadFromFile();
4952
4953   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
4954   if(!SM) return aResult._retn();
4955
4956   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
4957   if(!SDSM) return aResult._retn();
4958
4959   aResult->length(SDSM->NbElements());
4960
4961   SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
4962   int i = 0;
4963   while ( eIt->more() ) {
4964     aResult[i++] = eIt->next()->GetID();
4965   }
4966
4967   SMESH_CATCH( SMESH::throwCorbaException );
4968
4969   return aResult._retn();
4970 }
4971
4972 //=============================================================================
4973 /*!
4974  * Return ID of nodes for given sub-mesh
4975  * If param all==true - return all nodes, else -
4976  * Return only nodes on shapes.
4977  */
4978 //=============================================================================
4979
4980 SMESH::long_array* SMESH_Mesh_i::GetSubMeshNodesId(const CORBA::Long ShapeID,
4981                                                    CORBA::Boolean    all)
4982   throw (SALOME::SALOME_Exception)
4983 {
4984   SMESH::long_array_var aResult = new SMESH::long_array();
4985
4986   SMESH_TRY;
4987   if ( _preMeshInfo )
4988     _preMeshInfo->FullLoadFromFile();
4989
4990   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
4991   if(!SM) return aResult._retn();
4992
4993   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
4994   if(!SDSM) return aResult._retn();
4995
4996   set<int> theElems;
4997   if( !all || (SDSM->NbElements()==0) ) { // internal nodes or vertex submesh
4998     SMDS_NodeIteratorPtr nIt = SDSM->GetNodes();
4999     while ( nIt->more() ) {
5000       const SMDS_MeshNode* elem = nIt->next();
5001       theElems.insert( elem->GetID() );
5002     }
5003   }
5004   else { // all nodes of submesh elements
5005     SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
5006     while ( eIt->more() ) {
5007       const SMDS_MeshElement* anElem = eIt->next();
5008       SMDS_ElemIteratorPtr nIt = anElem->nodesIterator();
5009       while ( nIt->more() ) {
5010         const SMDS_MeshElement* elem = nIt->next();
5011         theElems.insert( elem->GetID() );
5012       }
5013     }
5014   }
5015
5016   aResult->length(theElems.size());
5017   set<int>::iterator itElem;
5018   int i = 0;
5019   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5020     aResult[i++] = *itElem;
5021
5022   SMESH_CATCH( SMESH::throwCorbaException );
5023
5024   return aResult._retn();
5025 }
5026
5027 //=============================================================================
5028 /*!
5029  * Return type of elements for given sub-mesh
5030  */
5031 //=============================================================================
5032
5033 SMESH::ElementType SMESH_Mesh_i::GetSubMeshElementType(const CORBA::Long ShapeID)
5034   throw (SALOME::SALOME_Exception)
5035 {
5036   SMESH::ElementType type = SMESH::ALL;
5037
5038   SMESH_TRY;
5039   if ( _preMeshInfo )
5040     _preMeshInfo->FullLoadFromFile();
5041
5042   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
5043   if(!SM) return SMESH::ALL;
5044
5045   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
5046   if(!SDSM) return SMESH::ALL;
5047
5048   if(SDSM->NbElements()==0)
5049     return (SM->GetSubShape().ShapeType() == TopAbs_VERTEX) ? SMESH::NODE : SMESH::ALL;
5050
5051   SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
5052   const SMDS_MeshElement* anElem = eIt->next();
5053
5054   type = ( SMESH::ElementType ) anElem->GetType();
5055
5056   SMESH_CATCH( SMESH::throwCorbaException );
5057
5058   return type;
5059 }
5060
5061
5062 //=============================================================================
5063 /*!
5064  * Return pointer to _impl as an integer value. Is called from constructor of SMESH_Client
5065  */
5066 //=============================================================================
5067
5068 CORBA::LongLong SMESH_Mesh_i::GetMeshPtr()
5069 {
5070   if ( _preMeshInfo )
5071     _preMeshInfo->FullLoadFromFile();
5072
5073   CORBA::LongLong pointeur = CORBA::LongLong(_impl);
5074   if ( MYDEBUG ) MESSAGE("CORBA::LongLong SMESH_Mesh_i::GetMeshPtr() "<<pointeur);
5075   return pointeur;
5076 }
5077
5078
5079 //=============================================================================
5080 /*!
5081  * Get XYZ coordinates of node as list of double
5082  * If there is not node for given ID - return empty list
5083  */
5084 //=============================================================================
5085
5086 SMESH::double_array* SMESH_Mesh_i::GetNodeXYZ(const CORBA::Long id)
5087 {
5088   if ( _preMeshInfo )
5089     _preMeshInfo->FullLoadFromFile();
5090
5091   SMESH::double_array_var aResult = new SMESH::double_array();
5092   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5093   if ( aMeshDS == NULL )
5094     return aResult._retn();
5095
5096   // find node
5097   const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
5098   if(!aNode)
5099     return aResult._retn();
5100
5101   // add coordinates
5102   aResult->length(3);
5103   aResult[0] = aNode->X();
5104   aResult[1] = aNode->Y();
5105   aResult[2] = aNode->Z();
5106   return aResult._retn();
5107 }
5108
5109
5110 //=============================================================================
5111 /*!
5112  * For given node return list of IDs of inverse elements
5113  * If there is not node for given ID - return empty list
5114  */
5115 //=============================================================================
5116
5117 SMESH::long_array* SMESH_Mesh_i::GetNodeInverseElements(const CORBA::Long  id,
5118                                                         SMESH::ElementType elemType)
5119 {
5120   if ( _preMeshInfo )
5121     _preMeshInfo->FullLoadFromFile();
5122
5123   SMESH::long_array_var aResult = new SMESH::long_array();
5124   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5125   if ( aMeshDS == NULL )
5126     return aResult._retn();
5127
5128   // find node
5129   const SMDS_MeshNode* aNode = aMeshDS->FindNode( id );
5130   if ( !aNode )
5131     return aResult._retn();
5132
5133   // find inverse elements
5134   SMDSAbs_ElementType type = SMDSAbs_ElementType( elemType );
5135   SMDS_ElemIteratorPtr eIt = aNode->GetInverseElementIterator( type );
5136   aResult->length( aNode->NbInverseElements( type ));
5137   for( int i = 0; eIt->more(); ++i )
5138   {
5139     const SMDS_MeshElement* elem = eIt->next();
5140     aResult[ i ] = elem->GetID();
5141   }
5142   return aResult._retn();
5143 }
5144
5145 //=============================================================================
5146 /*!
5147  * \brief Return position of a node on shape
5148  */
5149 //=============================================================================
5150
5151 SMESH::NodePosition* SMESH_Mesh_i::GetNodePosition(CORBA::Long NodeID)
5152 {
5153   if ( _preMeshInfo )
5154     _preMeshInfo->FullLoadFromFile();
5155
5156   SMESH::NodePosition* aNodePosition = new SMESH::NodePosition();
5157   aNodePosition->shapeID = 0;
5158   aNodePosition->shapeType = GEOM::SHAPE;
5159
5160   SMESHDS_Mesh* mesh = _impl->GetMeshDS();
5161   if ( !mesh ) return aNodePosition;
5162
5163   if ( const SMDS_MeshNode* aNode = mesh->FindNode(NodeID) )
5164   {
5165     if ( SMDS_PositionPtr pos = aNode->GetPosition() )
5166     {
5167       aNodePosition->shapeID = aNode->getshapeId();
5168       switch ( pos->GetTypeOfPosition() ) {
5169       case SMDS_TOP_EDGE:
5170         aNodePosition->shapeType = GEOM::EDGE;
5171         aNodePosition->params.length(1);
5172         aNodePosition->params[0] = SMDS_EdgePositionPtr( pos )->GetUParameter();
5173         break;
5174       case SMDS_TOP_FACE: {
5175         SMDS_FacePositionPtr fPos = pos;
5176         aNodePosition->shapeType = GEOM::FACE;
5177         aNodePosition->params.length(2);
5178         aNodePosition->params[0] = fPos->GetUParameter();
5179         aNodePosition->params[1] = fPos->GetVParameter();
5180         break;
5181       }
5182       case SMDS_TOP_VERTEX:
5183         aNodePosition->shapeType = GEOM::VERTEX;
5184         break;
5185       case SMDS_TOP_3DSPACE:
5186         if ( TopExp_Explorer(_impl->GetShapeToMesh(), TopAbs_SOLID).More() )
5187           aNodePosition->shapeType = GEOM::SOLID;
5188         else if ( TopExp_Explorer(_impl->GetShapeToMesh(), TopAbs_SHELL).More() )
5189           aNodePosition->shapeType = GEOM::SHELL;
5190         break;
5191       default:;
5192       }
5193     }
5194   }
5195   return aNodePosition;
5196 }
5197
5198 //=============================================================================
5199 /*!
5200  * \brief Return position of an element on shape
5201  */
5202 //=============================================================================
5203
5204 SMESH::ElementPosition SMESH_Mesh_i::GetElementPosition(CORBA::Long ElemID)
5205 {
5206   if ( _preMeshInfo )
5207     _preMeshInfo->FullLoadFromFile();
5208
5209   SMESH::ElementPosition anElementPosition;
5210   anElementPosition.shapeID = 0;
5211   anElementPosition.shapeType = GEOM::SHAPE;
5212
5213   SMESHDS_Mesh* mesh = _impl->GetMeshDS();
5214   if ( !mesh ) return anElementPosition;
5215
5216   if ( const SMDS_MeshElement* anElem = mesh->FindElement( ElemID ) )
5217   {
5218     anElementPosition.shapeID = anElem->getshapeId();
5219     const TopoDS_Shape& aSp = mesh->IndexToShape( anElem->getshapeId() );
5220     if ( !aSp.IsNull() ) {
5221       switch ( aSp.ShapeType() ) {
5222       case TopAbs_EDGE:
5223         anElementPosition.shapeType = GEOM::EDGE;
5224         break;
5225       case TopAbs_FACE:
5226         anElementPosition.shapeType = GEOM::FACE;
5227         break;
5228       case TopAbs_VERTEX:
5229         anElementPosition.shapeType = GEOM::VERTEX;
5230         break;
5231       case TopAbs_SOLID:
5232         anElementPosition.shapeType = GEOM::SOLID;
5233         break;
5234       case TopAbs_SHELL:
5235         anElementPosition.shapeType = GEOM::SHELL;
5236         break;
5237       default:;
5238       }
5239     }
5240   }
5241   return anElementPosition;
5242 }
5243
5244 //=============================================================================
5245 /*!
5246  * If given element is node return IDs of shape from position
5247  * If there is not node for given ID - return -1
5248  */
5249 //=============================================================================
5250
5251 CORBA::Long SMESH_Mesh_i::GetShapeID(const CORBA::Long id)
5252 {
5253   if ( _preMeshInfo )
5254     _preMeshInfo->FullLoadFromFile();
5255
5256   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5257   if ( aMeshDS == NULL )
5258     return -1;
5259
5260   // try to find node
5261   const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
5262   if(aNode) {
5263     return aNode->getshapeId();
5264   }
5265
5266   return -1;
5267 }
5268
5269
5270 //=============================================================================
5271 /*!
5272  * For given element return ID of result shape after
5273  * ::FindShape() from SMESH_MeshEditor
5274  * If there is not element for given ID - return -1
5275  */
5276 //=============================================================================
5277
5278 CORBA::Long SMESH_Mesh_i::GetShapeIDForElem(const CORBA::Long id)
5279 {
5280   if ( _preMeshInfo )
5281     _preMeshInfo->FullLoadFromFile();
5282
5283   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5284   if ( aMeshDS == NULL )
5285     return -1;
5286
5287   // try to find element
5288   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5289   if(!elem)
5290     return -1;
5291
5292   ::SMESH_MeshEditor aMeshEditor(_impl);
5293   int index = aMeshEditor.FindShape( elem );
5294   if(index>0)
5295     return index;
5296
5297   return -1;
5298 }
5299
5300
5301 //=============================================================================
5302 /*!
5303  * Return number of nodes for given element
5304  * If there is not element for given ID - return -1
5305  */
5306 //=============================================================================
5307
5308 CORBA::Long SMESH_Mesh_i::GetElemNbNodes(const CORBA::Long id)
5309 {
5310   if ( _preMeshInfo )
5311     _preMeshInfo->FullLoadFromFile();
5312
5313   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5314   if ( aMeshDS == NULL ) return -1;
5315   // try to find element
5316   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5317   if(!elem) return -1;
5318   return elem->NbNodes();
5319 }
5320
5321
5322 //=============================================================================
5323 /*!
5324  * Return ID of node by given index for given element
5325  * If there is not element for given ID - return -1
5326  * If there is not node for given index - return -2
5327  */
5328 //=============================================================================
5329
5330 CORBA::Long SMESH_Mesh_i::GetElemNode(const CORBA::Long id, const CORBA::Long index)
5331 {
5332   if ( _preMeshInfo )
5333     _preMeshInfo->FullLoadFromFile();
5334
5335   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5336   if ( aMeshDS == NULL ) return -1;
5337   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5338   if(!elem) return -1;
5339   if( index>=elem->NbNodes() || index<0 ) return -1;
5340   return elem->GetNode(index)->GetID();
5341 }
5342
5343 //=============================================================================
5344 /*!
5345  * Return IDs of nodes of given element
5346  */
5347 //=============================================================================
5348
5349 SMESH::long_array* SMESH_Mesh_i::GetElemNodes(const CORBA::Long id)
5350 {
5351   if ( _preMeshInfo )
5352     _preMeshInfo->FullLoadFromFile();
5353
5354   SMESH::long_array_var aResult = new SMESH::long_array();
5355   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() )
5356   {
5357     if ( const SMDS_MeshElement* elem = aMeshDS->FindElement(id) )
5358     {
5359       aResult->length( elem->NbNodes() );
5360       for ( CORBA::ULong i = 0; i < aResult->length(); ++i )
5361         if ( const SMDS_MeshNode* n = elem->GetNode( i ))
5362           aResult[ i ] = n->GetID();
5363     }
5364   }
5365   return aResult._retn();
5366 }
5367
5368 //=============================================================================
5369 /*!
5370  * Return true if given node is medium node
5371  * in given quadratic element
5372  */
5373 //=============================================================================
5374
5375 CORBA::Boolean SMESH_Mesh_i::IsMediumNode(const CORBA::Long ide, const CORBA::Long idn)
5376 {
5377   if ( _preMeshInfo )
5378     _preMeshInfo->FullLoadFromFile();
5379
5380   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5381   if ( aMeshDS == NULL ) return false;
5382   // try to find node
5383   const SMDS_MeshNode* aNode = aMeshDS->FindNode(idn);
5384   if(!aNode) return false;
5385   // try to find element
5386   const SMDS_MeshElement* elem = aMeshDS->FindElement(ide);
5387   if(!elem) return false;
5388
5389   return elem->IsMediumNode(aNode);
5390 }
5391
5392
5393 //=============================================================================
5394 /*!
5395  * Return true if given node is medium node
5396  * in one of quadratic elements
5397  */
5398 //=============================================================================
5399
5400 CORBA::Boolean SMESH_Mesh_i::IsMediumNodeOfAnyElem(const CORBA::Long idn,
5401                                                    SMESH::ElementType theElemType)
5402 {
5403   if ( _preMeshInfo )
5404     _preMeshInfo->FullLoadFromFile();
5405
5406   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5407   if ( aMeshDS == NULL ) return false;
5408
5409   // try to find node
5410   const SMDS_MeshNode* aNode = aMeshDS->FindNode(idn);
5411   if(!aNode) return false;
5412
5413   SMESH_MesherHelper aHelper( *(_impl) );
5414
5415   SMDSAbs_ElementType aType;
5416   if(theElemType==SMESH::EDGE) aType = SMDSAbs_Edge;
5417   else if(theElemType==SMESH::FACE) aType = SMDSAbs_Face;
5418   else if(theElemType==SMESH::VOLUME) aType = SMDSAbs_Volume;
5419   else aType = SMDSAbs_All;
5420
5421   return aHelper.IsMedium(aNode,aType);
5422 }
5423
5424
5425 //=============================================================================
5426 /*!
5427  * Return number of edges for given element
5428  */
5429 //=============================================================================
5430
5431 CORBA::Long SMESH_Mesh_i::ElemNbEdges(const CORBA::Long id)
5432 {
5433   if ( _preMeshInfo )
5434     _preMeshInfo->FullLoadFromFile();
5435
5436   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5437   if ( aMeshDS == NULL ) return -1;
5438   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5439   if(!elem) return -1;
5440   return elem->NbEdges();
5441 }
5442
5443
5444 //=============================================================================
5445 /*!
5446  * Return number of faces for given element
5447  */
5448 //=============================================================================
5449
5450 CORBA::Long SMESH_Mesh_i::ElemNbFaces(const CORBA::Long id)
5451 {
5452   if ( _preMeshInfo )
5453     _preMeshInfo->FullLoadFromFile();
5454
5455   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5456   if ( aMeshDS == NULL ) return -1;
5457   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5458   if(!elem) return -1;
5459   return elem->NbFaces();
5460 }
5461
5462 //================================================================================
5463 /*!
5464  * \brief Return nodes of given face (counted from zero) for given element.
5465  */
5466 //================================================================================
5467
5468 SMESH::long_array* SMESH_Mesh_i::GetElemFaceNodes(CORBA::Long  elemId,
5469                                                   CORBA::Short faceIndex)
5470 {
5471   if ( _preMeshInfo )
5472     _preMeshInfo->FullLoadFromFile();
5473
5474   SMESH::long_array_var aResult = new SMESH::long_array();
5475   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() )
5476   {
5477     if ( const SMDS_MeshElement* elem = aMeshDS->FindElement(elemId) )
5478     {
5479       SMDS_VolumeTool vtool( elem, /*skipCentralNodes = */false );
5480       if ( faceIndex < vtool.NbFaces() )
5481       {
5482         aResult->length( vtool.NbFaceNodes( faceIndex ));
5483         const SMDS_MeshNode** nn = vtool.GetFaceNodes( faceIndex );
5484         for ( CORBA::ULong i = 0; i < aResult->length(); ++i )
5485           aResult[ i ] = nn[ i ]->GetID();
5486       }
5487     }
5488   }
5489   return aResult._retn();
5490 }
5491
5492 //================================================================================
5493 /*!
5494  * \brief Return three components of normal of given mesh face.
5495  */
5496 //================================================================================
5497
5498 SMESH::double_array* SMESH_Mesh_i::GetFaceNormal(CORBA::Long    elemId,
5499                                                  CORBA::Boolean normalized)
5500 {
5501   if ( _preMeshInfo )
5502     _preMeshInfo->FullLoadFromFile();
5503
5504   SMESH::double_array_var aResult = new SMESH::double_array();
5505
5506   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5507   {
5508     gp_XYZ normal;
5509     if ( SMESH_MeshAlgos::FaceNormal( mesh->FindElement(elemId), normal, normalized ))
5510     {
5511       aResult->length( 3 );
5512       aResult[ 0 ] = normal.X();
5513       aResult[ 1 ] = normal.Y();
5514       aResult[ 2 ] = normal.Z();
5515     }
5516   }
5517   return aResult._retn();
5518 }
5519
5520 //================================================================================
5521 /*!
5522  * \brief Return an element based on all given nodes.
5523  */
5524 //================================================================================
5525
5526 CORBA::Long SMESH_Mesh_i::FindElementByNodes(const SMESH::long_array& nodes)
5527 {
5528   if ( _preMeshInfo )
5529     _preMeshInfo->FullLoadFromFile();
5530
5531   CORBA::Long elemID(0);
5532   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5533   {
5534     vector< const SMDS_MeshNode * > nn( nodes.length() );
5535     for ( CORBA::ULong i = 0; i < nodes.length(); ++i )
5536       if ( !( nn[i] = mesh->FindNode( nodes[i] )))
5537         return elemID;
5538
5539     const SMDS_MeshElement* elem = mesh->FindElement( nn, SMDSAbs_All, /*noMedium=*/false );
5540     if ( !elem && ( _impl->NbEdges  ( ORDER_QUADRATIC ) ||
5541                     _impl->NbFaces  ( ORDER_QUADRATIC ) ||
5542                     _impl->NbVolumes( ORDER_QUADRATIC )))
5543       elem = mesh->FindElement( nn, SMDSAbs_All, /*noMedium=*/true );
5544
5545     if ( elem ) elemID = CORBA::Long( elem->GetID() );
5546   }
5547   return elemID;
5548 }
5549
5550 //================================================================================
5551 /*!
5552  * \brief Return elements including all given nodes.
5553  */
5554 //================================================================================
5555
5556 SMESH::long_array* SMESH_Mesh_i::GetElementsByNodes(const SMESH::long_array& nodes,
5557                                                     SMESH::ElementType       elemType)
5558 {
5559   if ( _preMeshInfo )
5560     _preMeshInfo->FullLoadFromFile();
5561
5562   SMESH::long_array_var result = new SMESH::long_array();
5563
5564   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5565   {
5566     vector< const SMDS_MeshNode * > nn( nodes.length() );
5567     for ( CORBA::ULong i = 0; i < nodes.length(); ++i )
5568       nn[i] = mesh->FindNode( nodes[i] );
5569
5570     std::vector<const SMDS_MeshElement *> elems;
5571     mesh->GetElementsByNodes( nn, elems, (SMDSAbs_ElementType) elemType );
5572     result->length( elems.size() );
5573     for ( size_t i = 0; i < elems.size(); ++i )
5574       result[i] = elems[i]->GetID();
5575   }
5576   return result._retn();
5577 }
5578
5579 //=============================================================================
5580 /*!
5581  * Return true if given element is polygon
5582  */
5583 //=============================================================================
5584
5585 CORBA::Boolean SMESH_Mesh_i::IsPoly(const CORBA::Long id)
5586 {
5587   if ( _preMeshInfo )
5588     _preMeshInfo->FullLoadFromFile();
5589
5590   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5591   if ( aMeshDS == NULL ) return false;
5592   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5593   if(!elem) return false;
5594   return elem->IsPoly();
5595 }
5596
5597
5598 //=============================================================================
5599 /*!
5600  * Return true if given element is quadratic
5601  */
5602 //=============================================================================
5603
5604 CORBA::Boolean SMESH_Mesh_i::IsQuadratic(const CORBA::Long id)
5605 {
5606   if ( _preMeshInfo )
5607     _preMeshInfo->FullLoadFromFile();
5608
5609   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5610   if ( aMeshDS == NULL ) return false;
5611   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5612   if(!elem) return false;
5613   return elem->IsQuadratic();
5614 }
5615
5616 //=============================================================================
5617 /*!
5618  * Return diameter of ball discrete element or zero in case of an invalid \a id
5619  */
5620 //=============================================================================
5621
5622 CORBA::Double SMESH_Mesh_i::GetBallDiameter(CORBA::Long id)
5623 {
5624   if ( _preMeshInfo )
5625     _preMeshInfo->FullLoadFromFile();
5626
5627   if ( const SMDS_BallElement* ball =
5628        SMDS_Mesh::DownCast<SMDS_BallElement>( _impl->GetMeshDS()->FindElement( id )))
5629     return ball->GetDiameter();
5630
5631   return 0;
5632 }
5633
5634 //=============================================================================
5635 /*!
5636  * Return bary center for given element
5637  */
5638 //=============================================================================
5639
5640 SMESH::double_array* SMESH_Mesh_i::BaryCenter(const CORBA::Long id)
5641 {
5642   if ( _preMeshInfo )
5643     _preMeshInfo->FullLoadFromFile();
5644
5645   SMESH::double_array_var aResult = new SMESH::double_array();
5646   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5647   if ( aMeshDS == NULL )
5648     return aResult._retn();
5649
5650   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5651   if(!elem)
5652     return aResult._retn();
5653
5654   if(elem->GetType()==SMDSAbs_Volume) {
5655     SMDS_VolumeTool aTool;
5656     if(aTool.Set(elem)) {
5657       aResult->length(3);
5658       if (!aTool.GetBaryCenter( aResult[0], aResult[1], aResult[2]) )
5659         aResult->length(0);
5660     }
5661   }
5662   else {
5663     SMDS_ElemIteratorPtr anIt = elem->nodesIterator();
5664     int nbn = 0;
5665     double x=0., y=0., z=0.;
5666     for(; anIt->more(); ) {
5667       nbn++;
5668       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(anIt->next());
5669       x += aNode->X();
5670       y += aNode->Y();
5671       z += aNode->Z();
5672     }
5673     if(nbn>0) {
5674       // add coordinates
5675       aResult->length(3);
5676       aResult[0] = x/nbn;
5677       aResult[1] = y/nbn;
5678       aResult[2] = z/nbn;
5679     }
5680   }
5681
5682   return aResult._retn();
5683 }
5684
5685 //================================================================================
5686 /*!
5687  * \brief Create a group of elements preventing computation of a sub-shape
5688  */
5689 //================================================================================
5690
5691 SMESH::ListOfGroups*
5692 SMESH_Mesh_i::MakeGroupsOfBadInputElements( int         theSubShapeID,
5693                                             const char* theGroupName )
5694   throw ( SALOME::SALOME_Exception )
5695 {
5696   Unexpect aCatch(SALOME_SalomeException);
5697
5698   if ( !theGroupName || strlen( theGroupName) == 0 )
5699     THROW_SALOME_CORBA_EXCEPTION( "empty group name",SALOME::BAD_PARAM );
5700
5701   SMESH::ListOfGroups_var groups = new SMESH::ListOfGroups;
5702   ::SMESH_MeshEditor::ElemFeatures elemType;
5703
5704   // submesh by subshape id
5705   if ( !_impl->HasShapeToMesh() ) theSubShapeID = 1;
5706   if ( SMESH_subMesh * sm = _impl->GetSubMeshContaining( theSubShapeID ))
5707   {
5708     // compute error
5709     SMESH_ComputeErrorPtr error = sm->GetComputeError();
5710     if ( error && error->HasBadElems() )
5711     {
5712       // sort bad elements by type
5713       vector< const SMDS_MeshElement* > elemsByType[ SMDSAbs_NbElementTypes ];
5714       const list<const SMDS_MeshElement*>& badElems =
5715         static_cast<SMESH_BadInputElements*>( error.get() )->myBadElements;
5716       list<const SMDS_MeshElement*>::const_iterator elemIt  = badElems.begin();
5717       list<const SMDS_MeshElement*>::const_iterator elemEnd = badElems.end();
5718       for ( ; elemIt != elemEnd; ++elemIt )
5719       {
5720         const SMDS_MeshElement* elem = *elemIt;
5721         if ( !elem ) continue;
5722
5723         if ( elem->GetID() < 1 )
5724         {
5725           // elem is a temporary element, make a real element
5726           vector< const SMDS_MeshNode* > nodes;
5727           SMDS_NodeIteratorPtr nIt = elem->nodeIterator();
5728           while ( nIt->more() && elem )
5729           {
5730             nodes.push_back( nIt->next() );
5731             if ( nodes.back()->GetID() < 1 )
5732               elem = 0;  // a temporary element on temporary nodes
5733           }
5734           if ( elem )
5735           {
5736             ::SMESH_MeshEditor editor( _impl );
5737             elem = editor.AddElement( nodes, elemType.Init( elem ));
5738           }
5739         }
5740         if ( elem )
5741           elemsByType[ elem->GetType() ].push_back( elem );
5742       }
5743
5744       // how many groups to create?
5745       int nbTypes = 0;
5746       for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
5747         nbTypes += int( !elemsByType[ i ].empty() );
5748       groups->length( nbTypes );
5749
5750       // create groups
5751       for ( int i = 0, iG = -1; i < SMDSAbs_NbElementTypes; ++i )
5752       {
5753         vector< const SMDS_MeshElement* >& elems = elemsByType[ i ];
5754         if ( elems.empty() ) continue;
5755
5756         groups[ ++iG ] = createGroup( SMESH::ElementType(i), theGroupName );
5757         if ( _gen_i->CanPublishInStudy( groups[ iG ] ))
5758         {
5759           SMESH::SMESH_Mesh_var mesh = _this();
5760           SALOMEDS::SObject_wrap aSO =
5761             _gen_i->PublishGroup( mesh, groups[ iG ],
5762                                  GEOM::GEOM_Object::_nil(), theGroupName);
5763         }
5764         SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( groups[ iG ]);
5765         if ( !grp_i ) continue;
5766
5767         if ( SMESHDS_Group*  grpDS = dynamic_cast< SMESHDS_Group* >( grp_i->GetGroupDS() ))
5768           for ( size_t iE = 0; iE < elems.size(); ++iE )
5769             grpDS->SMDSGroup().Add( elems[ iE ]);
5770       }
5771     }
5772   }
5773
5774   return groups._retn();
5775 }
5776
5777 //=============================================================================
5778 /*!
5779  * Create and publish group servants if any groups were imported or created anyhow
5780  */
5781 //=============================================================================
5782
5783 void SMESH_Mesh_i::CreateGroupServants()
5784 {
5785   SMESH::SMESH_Mesh_var aMesh = _this();
5786
5787   set<int> addedIDs;
5788   ::SMESH_Mesh::GroupIteratorPtr groupIt = _impl->GetGroups();
5789   while ( groupIt->more() )
5790   {
5791     ::SMESH_Group* group = groupIt->next();
5792     int             anId = group->GetID();
5793
5794     map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.find(anId);
5795     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
5796       continue;
5797     addedIDs.insert( anId );
5798
5799     SMESH_GroupBase_i* aGroupImpl;
5800     TopoDS_Shape       shape;
5801     if ( SMESHDS_GroupOnGeom* groupOnGeom =
5802          dynamic_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() ))
5803     {
5804       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
5805       shape      = groupOnGeom->GetShape();
5806     }
5807     else {
5808       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
5809     }
5810
5811     SMESH::SMESH_GroupBase_var groupVar = aGroupImpl->_this();
5812     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( groupVar );
5813     aGroupImpl->Register();
5814
5815     // register CORBA object for persistence
5816     int nextId = _gen_i->RegisterObject( groupVar );
5817     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
5818     else        { nextId = 0; } // avoid "unused variable" warning in release mode
5819
5820     // publishing the groups in the study
5821     GEOM::GEOM_Object_var shapeVar = _gen_i->ShapeToGeomObject( shape );
5822     _gen_i->PublishGroup( aMesh, groupVar, shapeVar, group->GetName());
5823   }
5824
5825   if ( !addedIDs.empty() )
5826   {
5827     // python dump
5828     map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.begin();
5829     for ( int index = 0; i_grp != _mapGroups.end(); ++index, ++i_grp )
5830     {
5831       set<int>::iterator it = addedIDs.find( i_grp->first );
5832       if ( it != addedIDs.end() )
5833       {
5834         TPythonDump() << i_grp->second << " = " << aMesh << ".GetGroups()[ "<< index << " ]";
5835         addedIDs.erase( it );
5836         if ( addedIDs.empty() )
5837           break;
5838       }
5839     }
5840   }
5841 }
5842
5843 //=============================================================================
5844 /*!
5845  * \brief Return true if all sub-meshes are computed OK - to update an icon
5846  */
5847 //=============================================================================
5848
5849 bool SMESH_Mesh_i::IsComputedOK()
5850 {
5851   return _impl->IsComputedOK();
5852 }
5853
5854 //=============================================================================
5855 /*!
5856  * \brief Return groups cantained in _mapGroups by their IDs
5857  */
5858 //=============================================================================
5859
5860 SMESH::ListOfGroups* SMESH_Mesh_i::GetGroups(const list<int>& groupIDs) const
5861 {
5862   int nbGroups = groupIDs.size();
5863   SMESH::ListOfGroups_var aList = new SMESH::ListOfGroups();
5864   aList->length( nbGroups );
5865
5866   list<int>::const_iterator ids = groupIDs.begin();
5867   for ( nbGroups = 0; ids != groupIDs.end(); ++ids )
5868   {
5869     map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator it = _mapGroups.find( *ids );
5870     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
5871       aList[nbGroups++] = SMESH::SMESH_GroupBase::_duplicate( it->second );
5872   }
5873   aList->length( nbGroups );
5874   return aList._retn();
5875 }
5876
5877 //=============================================================================
5878 /*!
5879  * \brief Return information about imported file
5880  */
5881 //=============================================================================
5882
5883 SMESH::MedFileInfo* SMESH_Mesh_i::GetMEDFileInfo()
5884 {
5885   SMESH::MedFileInfo_var res( _medFileInfo );
5886   if ( !res.operator->() ) {
5887     res = new SMESH::MedFileInfo;
5888     res->fileName = "";
5889     res->fileSize = res->major = res->minor = res->release = -1;
5890   }
5891   return res._retn();
5892 }
5893
5894 //=======================================================================
5895 //function : FileInfoToString
5896 //purpose  : Persistence of file info
5897 //=======================================================================
5898
5899 std::string SMESH_Mesh_i::FileInfoToString()
5900 {
5901   std::string s;
5902   if ( &_medFileInfo.in() && _medFileInfo->fileName[0] )
5903   {
5904     s = SMESH_Comment( _medFileInfo->fileSize )
5905       << " " << _medFileInfo->major
5906       << " " << _medFileInfo->minor
5907       << " " << _medFileInfo->release
5908       << " " << _medFileInfo->fileName;
5909   }
5910   return s;
5911 }
5912
5913 //=======================================================================
5914 //function : FileInfoFromString
5915 //purpose  : Persistence of file info
5916 //=======================================================================
5917
5918 void SMESH_Mesh_i::FileInfoFromString(const std::string& info)
5919 {
5920   std::string size, major, minor, release, fileName;
5921   std::istringstream is(info);
5922   is >> size >> major >> minor >> release;
5923   fileName = info.data() + ( size.size()   + 1 +
5924                              major.size()  + 1 +
5925                              minor.size()  + 1 +
5926                              release.size()+ 1 );
5927
5928   _medFileInfo           = new SMESH::MedFileInfo();
5929   _medFileInfo->fileName = fileName.c_str();
5930   _medFileInfo->fileSize = atoi( size.c_str() );
5931   _medFileInfo->major    = atoi( major.c_str() );
5932   _medFileInfo->minor    = atoi( minor.c_str() );
5933   _medFileInfo->release  = atoi( release.c_str() );
5934 }
5935
5936 //=============================================================================
5937 /*!
5938  * \brief Pass names of mesh groups from study to mesh DS
5939  */
5940 //=============================================================================
5941
5942 void SMESH_Mesh_i::checkGroupNames()
5943 {
5944   int nbGrp = NbGroups();
5945   if ( !nbGrp )
5946     return;
5947
5948   SMESH::ListOfGroups* grpList = 0;
5949   // avoid dump of "GetGroups"
5950   {
5951     // store python dump into a local variable inside local scope
5952     SMESH::TPythonDump pDump; // do not delete this line of code
5953     grpList = GetGroups();
5954   }
5955
5956   for ( int gIndx = 0; gIndx < nbGrp; gIndx++ ) {
5957     SMESH::SMESH_GroupBase_ptr aGrp = (*grpList)[ gIndx ];
5958     if ( !aGrp )
5959       continue;
5960     SALOMEDS::SObject_wrap aGrpSO = _gen_i->ObjectToSObject( aGrp );
5961     if ( aGrpSO->_is_nil() )
5962       continue;
5963     // correct name of the mesh group if necessary
5964     const char* guiName = aGrpSO->GetName();
5965     if ( strcmp(guiName, aGrp->GetName()) )
5966       aGrp->SetName( guiName );
5967   }
5968 }
5969
5970 //=============================================================================
5971 /*!
5972  * \brief Set list of notebook variables used for Mesh operations separated by ":" symbol
5973  */
5974 //=============================================================================
5975 void SMESH_Mesh_i::SetParameters(const char* theParameters)
5976 {
5977   SMESH_Gen_i::GetSMESHGen()->UpdateParameters( CORBA::Object_var( _this() ).in(),
5978                                                 theParameters );
5979 }
5980
5981 //=============================================================================
5982 /*!
5983  * \brief Return list of notebook variables used for Mesh operations separated by ":" symbol
5984  */
5985 //=============================================================================
5986
5987 char* SMESH_Mesh_i::GetParameters()
5988 {
5989   return SMESH_Gen_i::GetSMESHGen()->GetParameters( SMESH::SMESH_Mesh_var( _this()) );
5990 }
5991
5992 //=============================================================================
5993 /*!
5994  * \brief Return list of notebook variables used for last Mesh operation
5995  */
5996 //=============================================================================
5997 SMESH::string_array* SMESH_Mesh_i::GetLastParameters()
5998 {
5999   SMESH::string_array_var aResult = new SMESH::string_array();
6000   SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen();
6001   if(gen) {
6002     CORBA::String_var aParameters = GetParameters();
6003     SALOMEDS::ListOfListOfStrings_var aSections = SMESH_Gen_i::getStudyServant()->ParseVariables(aParameters);
6004     if ( aSections->length() > 0 ) {
6005       SALOMEDS::ListOfStrings aVars = aSections[ aSections->length() - 1 ];
6006       aResult->length( aVars.length() );
6007       for ( CORBA::ULong i = 0;i < aVars.length(); i++ )
6008         aResult[i] = CORBA::string_dup( aVars[i] );
6009     }
6010   }
6011   return aResult._retn();
6012 }
6013
6014 //================================================================================
6015 /*!
6016  * \brief Return types of elements it contains
6017  */
6018 //================================================================================
6019
6020 SMESH::array_of_ElementType* SMESH_Mesh_i::GetTypes()
6021 {
6022   if ( _preMeshInfo )
6023     return _preMeshInfo->GetTypes();
6024
6025   SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType;
6026
6027   types->length( 5 );
6028   int nbTypes = 0;
6029   if (_impl->NbEdges())      types[nbTypes++] = SMESH::EDGE;
6030   if (_impl->NbFaces())      types[nbTypes++] = SMESH::FACE;
6031   if (_impl->NbVolumes())    types[nbTypes++] = SMESH::VOLUME;
6032   if (_impl->Nb0DElements()) types[nbTypes++] = SMESH::ELEM0D;
6033   if (_impl->NbBalls())      types[nbTypes++] = SMESH::BALL;
6034   if (_impl->NbNodes() &&
6035       nbTypes == 0 )         types[nbTypes++] = SMESH::NODE;
6036   types->length( nbTypes );
6037
6038   return types._retn();
6039 }
6040
6041 //================================================================================
6042 /*!
6043  * \brief Return self
6044  */
6045 //================================================================================
6046
6047 SMESH::SMESH_Mesh_ptr SMESH_Mesh_i::GetMesh()
6048 {
6049   return SMESH::SMESH_Mesh::_duplicate( _this() );
6050 }
6051
6052 //================================================================================
6053 /*!
6054  * \brief Return false if GetMeshInfo() return incorrect information that may
6055  *        happen if mesh data is not yet fully loaded from the file of study.
6056  * 
6057  * 
6058  */
6059 //================================================================================
6060
6061 bool SMESH_Mesh_i::IsMeshInfoCorrect()
6062 {
6063   return _preMeshInfo ? _preMeshInfo->IsMeshInfoCorrect() : true;
6064 }
6065
6066 //=============================================================================
6067 /*!
6068  * \brief Return number of mesh elements per each \a EntityType
6069  */
6070 //=============================================================================
6071
6072 SMESH::long_array* SMESH_Mesh_i::GetMeshInfo()
6073 {
6074   if ( _preMeshInfo )
6075     return _preMeshInfo->GetMeshInfo();
6076
6077   SMESH::long_array_var aRes = new SMESH::long_array();
6078   aRes->length(SMESH::Entity_Last);
6079   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
6080     aRes[i] = 0;
6081   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
6082   if (!aMeshDS)
6083     return aRes._retn();
6084   const SMDS_MeshInfo& aMeshInfo = aMeshDS->GetMeshInfo();
6085   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
6086     aRes[i] = aMeshInfo.NbEntities((SMDSAbs_EntityType)i);
6087   return aRes._retn();
6088 }
6089
6090 //=============================================================================
6091 /*!
6092  * \brief Return number of mesh elements per each \a ElementType
6093  */
6094 //=============================================================================
6095
6096 SMESH::long_array* SMESH_Mesh_i::GetNbElementsByType()
6097 {
6098   SMESH::long_array_var aRes = new SMESH::long_array();
6099   aRes->length(SMESH::NB_ELEMENT_TYPES);
6100   for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
6101     aRes[ i ] = 0;
6102
6103   const SMDS_MeshInfo* meshInfo = 0;
6104   if ( _preMeshInfo )
6105     meshInfo = _preMeshInfo;
6106   else if ( SMESHDS_Mesh* meshDS = _impl->GetMeshDS() )
6107     meshInfo = & meshDS->GetMeshInfo();
6108
6109   if (meshInfo)
6110     for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
6111       aRes[i] = meshInfo->NbElements((SMDSAbs_ElementType)i);
6112
6113   return aRes._retn();
6114 }
6115
6116 //=============================================================================
6117 /*
6118  * Collect statistic of mesh elements given by iterator
6119  */
6120 //=============================================================================
6121
6122 void SMESH_Mesh_i::CollectMeshInfo(const SMDS_ElemIteratorPtr theItr,
6123                                    SMESH::long_array&         theInfo)
6124 {
6125   if (!theItr) return;
6126   while (theItr->more())
6127     theInfo[ theItr->next()->GetEntityType() ]++;
6128 }
6129 //=============================================================================
6130 /*
6131  * Return mesh unstructed grid information.
6132  */
6133 //=============================================================================
6134
6135 SALOMEDS::TMPFile* SMESH_Mesh_i::GetVtkUgStream()
6136 {
6137   SALOMEDS::TMPFile_var SeqFile;
6138   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() ) {
6139     SMDS_UnstructuredGrid* aGrid = aMeshDS->GetGrid();
6140     if(aGrid) {
6141       vtkUnstructuredGridWriter* aWriter = vtkUnstructuredGridWriter::New();
6142       aWriter->WriteToOutputStringOn();
6143       aWriter->SetInputData(aGrid);
6144       aWriter->SetFileTypeToBinary();
6145       aWriter->Write();
6146       char* str = aWriter->GetOutputString();
6147       int size = aWriter->GetOutputStringLength();
6148
6149       //Allocate octet buffer of required size
6150       CORBA::Octet* OctetBuf = SALOMEDS::TMPFile::allocbuf(size);
6151       //Copy ostrstream content to the octet buffer
6152       memcpy(OctetBuf, str, size);
6153       //Create and return TMPFile
6154       SeqFile = new SALOMEDS::TMPFile(size, size, OctetBuf, 1);
6155       aWriter->Delete();
6156     }
6157   }
6158   return SeqFile._retn();
6159 }
6160
6161 //=============================================================================
6162 namespace /* Iterators used in SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_var obj,
6163            *                                             SMESH::ElementType        type) */
6164 {
6165   using namespace SMESH::Controls;
6166   //-----------------------------------------------------------------------------
6167   struct PredicateIterator : public SMDS_ElemIterator
6168   {
6169     SMDS_ElemIteratorPtr    _elemIter;
6170     PredicatePtr            _predicate;
6171     const SMDS_MeshElement* _elem;
6172     SMDSAbs_ElementType     _type;
6173
6174     PredicateIterator( SMDS_ElemIteratorPtr iterator,
6175                        PredicatePtr         predicate,
6176                        SMDSAbs_ElementType  type):
6177       _elemIter(iterator), _predicate(predicate), _type(type)
6178     {
6179       next();
6180     }
6181     virtual bool more()
6182     {
6183       return _elem;
6184     }
6185     virtual const SMDS_MeshElement* next()
6186     {
6187       const SMDS_MeshElement* res = _elem;
6188       _elem = 0;
6189       while ( _elemIter->more() && !_elem )
6190       {
6191         if ((_elem = _elemIter->next()) &&
6192             (( _type != SMDSAbs_All && _type != _elem->GetType() ) ||
6193              ( !_predicate->IsSatisfy( _elem->GetID() ))))
6194           _elem = 0;
6195       }
6196       return res;
6197     }
6198   };
6199
6200   //-----------------------------------------------------------------------------
6201   struct IDSourceIterator : public SMDS_ElemIterator
6202   {
6203     const CORBA::Long*        _idPtr;
6204     const CORBA::Long*        _idEndPtr;
6205     SMESH::long_array_var     _idArray;
6206     const SMDS_Mesh*          _mesh;
6207     const SMDSAbs_ElementType _type;
6208     const SMDS_MeshElement*   _elem;
6209
6210     IDSourceIterator( const SMDS_Mesh*    mesh,
6211                       const CORBA::Long*  ids,
6212                       const int           nbIds,
6213                       SMDSAbs_ElementType type):
6214       _idPtr( ids ), _idEndPtr( ids + nbIds ), _mesh( mesh ), _type( type ), _elem( 0 )
6215     {
6216       if ( _idPtr && nbIds && _mesh )
6217         next();
6218     }
6219     IDSourceIterator( const SMDS_Mesh*    mesh,
6220                       SMESH::long_array*  idArray,
6221                       SMDSAbs_ElementType type):
6222       _idPtr( 0 ), _idEndPtr( 0 ), _idArray( idArray), _mesh( mesh ), _type( type ), _elem( 0 )
6223     {
6224       if ( idArray && _mesh )
6225       {
6226         _idPtr    = &_idArray[0];
6227         _idEndPtr = _idPtr + _idArray->length();
6228         next();
6229       }
6230     }
6231     virtual bool more()
6232     {
6233       return _elem;
6234     }
6235     virtual const SMDS_MeshElement* next()
6236     {
6237       const SMDS_MeshElement* res = _elem;
6238       _elem = 0;
6239       while ( _idPtr < _idEndPtr && !_elem )
6240       {
6241         if ( _type == SMDSAbs_Node )
6242         {
6243           _elem = _mesh->FindNode( *_idPtr++ );
6244         }
6245         else if ((_elem = _mesh->FindElement( *_idPtr++ )) &&
6246                  (_elem->GetType() != _type && _type != SMDSAbs_All ))
6247         {
6248           _elem = 0;
6249         }
6250       }
6251       return res;
6252     }
6253   };
6254   //-----------------------------------------------------------------------------
6255
6256   struct NodeOfElemIterator : public SMDS_ElemIterator
6257   {
6258     TColStd_MapOfInteger    _checkedNodeIDs;
6259     SMDS_ElemIteratorPtr    _elemIter;
6260     SMDS_ElemIteratorPtr    _nodeIter;
6261     const SMDS_MeshElement* _node;
6262
6263     NodeOfElemIterator( SMDS_ElemIteratorPtr iter ): _elemIter( iter ), _node( 0 )
6264     {
6265       if ( _elemIter && _elemIter->more() )
6266       {
6267         _nodeIter = _elemIter->next()->nodesIterator();
6268         next();
6269       }
6270     }
6271     virtual bool more()
6272     {
6273       return _node;
6274     }
6275     virtual const SMDS_MeshElement* next()
6276     {
6277       const SMDS_MeshElement* res = _node;
6278       _node = 0;
6279       while ( !_node && ( _elemIter->more() || _nodeIter->more() ))
6280       {
6281         if ( _nodeIter->more() )
6282         {
6283           _node = _nodeIter->next();
6284           if ( !_checkedNodeIDs.Add( _node->GetID() ))
6285             _node = 0;
6286         }
6287         else
6288         {
6289           _nodeIter = _elemIter->next()->nodesIterator();
6290         }
6291       }
6292       return res;
6293     }
6294   };
6295 }
6296
6297 //=============================================================================
6298 /*
6299  * Return iterator on elements of given type in given object
6300  */
6301 //=============================================================================
6302
6303 SMDS_ElemIteratorPtr SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_ptr theObject,
6304                                                SMESH::ElementType        theType)
6305 {
6306   SMDS_ElemIteratorPtr  elemIt;
6307   bool                  typeOK = ( theType == SMESH::ALL );
6308   SMDSAbs_ElementType elemType = SMDSAbs_ElementType( theType );
6309
6310   SMESH::SMESH_Mesh_var meshVar = theObject->GetMesh();
6311   SMESH_Mesh_i*          mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( meshVar );
6312   if ( !mesh_i ) return elemIt;
6313   SMESHDS_Mesh*          meshDS = mesh_i->GetImpl().GetMeshDS();
6314
6315   if ( SMESH::DownCast<SMESH_Mesh_i*>( theObject ))
6316   {
6317     elemIt = meshDS->elementsIterator( elemType );
6318     typeOK = true;
6319   }
6320   else if ( SMESH_subMesh_i* submesh_i = SMESH::DownCast<SMESH_subMesh_i*>( theObject ))
6321   {
6322     SMESHDS_SubMesh* sm = ((SMESHDS_Mesh*) meshDS)->MeshElements( submesh_i->GetId() );
6323     if ( sm )
6324     {
6325       elemIt = sm->GetElements();
6326       if ( elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
6327       {
6328         typeOK = ( elemIt && elemIt->more() && elemIt->next()->GetType() == elemType );
6329         elemIt = typeOK ? sm->GetElements() : SMDS_ElemIteratorPtr();
6330       }
6331     }
6332   }
6333   else if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( theObject ))
6334   {
6335     SMESHDS_GroupBase* groupDS = group_i->GetGroupDS();
6336     if ( groupDS && ( elemType == groupDS->GetType()  ||
6337                       elemType == SMDSAbs_Node ||
6338                       elemType == SMDSAbs_All ))
6339     {
6340       elemIt = groupDS->GetElements();
6341       typeOK = ( groupDS->GetType() == elemType || elemType == SMDSAbs_All );
6342     }
6343   }
6344   else if ( SMESH::Filter_i* filter_i = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
6345   {
6346     if ( filter_i->GetElementType() == theType ||
6347          filter_i->GetElementType() == SMESH::ALL ||
6348          elemType == SMDSAbs_Node ||
6349          elemType == SMDSAbs_All)
6350     {
6351       SMESH::Predicate_i* pred_i = filter_i->GetPredicate_i();
6352       if ( pred_i && pred_i->GetPredicate() )
6353       {
6354         SMDSAbs_ElementType filterType = SMDSAbs_ElementType( filter_i->GetElementType() );
6355         SMDS_ElemIteratorPtr allElemIt = meshDS->elementsIterator( filterType );
6356         SMDSAbs_ElementType   iterType = elemType == SMDSAbs_Node ? filterType : elemType;
6357         elemIt = SMDS_ElemIteratorPtr
6358           ( new PredicateIterator( allElemIt, pred_i->GetPredicate(), iterType ));
6359         typeOK = ( elemType == SMDSAbs_Node ? filterType == SMDSAbs_Node : elemIt->more() );
6360       }
6361     }
6362   }
6363   else
6364   {
6365     SMESH::array_of_ElementType_var types = theObject->GetTypes();
6366     const bool                    isNodes = ( types->length() == 1 && types[0] == SMESH::NODE );
6367     if ( isNodes && elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
6368       return elemIt;
6369     SMDSAbs_ElementType iterType = isNodes ? SMDSAbs_Node : elemType;
6370     if ( SMESH_MeshEditor_i::IsTemporaryIDSource( theObject ))
6371     {
6372       int nbIds;
6373       if ( CORBA::Long* ids = SMESH_MeshEditor_i::GetTemporaryIDs( theObject, nbIds ))
6374         elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids, nbIds, iterType ));
6375     }
6376     else
6377     {
6378       SMESH::long_array_var ids = theObject->GetIDs();
6379       elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids._retn(), iterType ));
6380     }
6381     typeOK = ( isNodes == ( elemType == SMDSAbs_Node )) || ( elemType == SMDSAbs_All );
6382   }
6383
6384   if ( elemIt && elemIt->more() && !typeOK )
6385   {
6386     if ( elemType == SMDSAbs_Node )
6387     {
6388       elemIt = SMDS_ElemIteratorPtr( new NodeOfElemIterator( elemIt ));
6389     }
6390     else
6391     {
6392       elemIt = SMDS_ElemIteratorPtr();
6393     }
6394   }
6395   return elemIt;
6396 }
6397
6398 //=============================================================================
6399 namespace // Finding concurrent hypotheses
6400 //=============================================================================
6401 {
6402
6403 /*!
6404  * \brief mapping of mesh dimension into shape type
6405  */
6406 TopAbs_ShapeEnum shapeTypeByDim(const int theDim)
6407 {
6408   TopAbs_ShapeEnum aType = TopAbs_SOLID;
6409   switch ( theDim ) {
6410   case 0: aType = TopAbs_VERTEX; break;
6411   case 1: aType = TopAbs_EDGE; break;
6412   case 2: aType = TopAbs_FACE; break;
6413   case 3:
6414   default:aType = TopAbs_SOLID; break;
6415   }
6416   return aType;
6417 }
6418
6419 //-----------------------------------------------------------------------------
6420 /*!
6421  * \brief Internal structure used to find concurrent submeshes
6422  *
6423  * It represents a pair < submesh, concurrent dimension >, where
6424  * 'concurrent dimension' is dimension of shape where the submesh can concurrent
6425  *  with another submesh. In other words, it is dimension of a hypothesis assigned
6426  *  to submesh.
6427  */
6428 class SMESH_DimHyp
6429 {
6430  public:
6431   //! fields
6432   int _dim;    //!< a dimension the algo can build (concurrent dimension)
6433   int _ownDim; //!< dimension of shape of _subMesh (>=_dim)
6434   TopTools_MapOfShape  _shapeMap; //!< [sub-]shapes of dimension == _dim
6435   const SMESH_subMesh* _subMesh;
6436   list<const SMESHDS_Hypothesis*> _hypotheses; //!< algo is first, then its parameters
6437
6438   //-----------------------------------------------------------------------------
6439   // Return the algorithm
6440   const SMESH_Algo* GetAlgo() const
6441   { return _hypotheses.empty() ? 0 : dynamic_cast<const SMESH_Algo*>( _hypotheses.front() ); }
6442
6443   //-----------------------------------------------------------------------------
6444   //! Constructors
6445   SMESH_DimHyp(const SMESH_subMesh* theSubMesh,
6446                const int            theDim,
6447                const TopoDS_Shape&  theShape)
6448   {
6449     _subMesh = theSubMesh;
6450     SetShape( theDim, theShape );
6451   }
6452
6453   //-----------------------------------------------------------------------------
6454   //! set shape
6455   void SetShape(const int           theDim,
6456                 const TopoDS_Shape& theShape)
6457   {
6458     _dim = theDim;
6459     _ownDim = SMESH_Gen::GetShapeDim(theShape);
6460     if (_dim >= _ownDim)
6461       _shapeMap.Add( theShape );
6462     else {
6463       TopExp_Explorer anExp( theShape, shapeTypeByDim(theDim) );
6464       for( ; anExp.More(); anExp.Next() )
6465         _shapeMap.Add( anExp.Current() );
6466     }
6467   }
6468
6469   //-----------------------------------------------------------------------------
6470   //! Check sharing of sub-shapes
6471   static bool isShareSubShapes(const TopTools_MapOfShape& theToCheck,
6472                                const TopTools_MapOfShape& theToFind,
6473                                const TopAbs_ShapeEnum     theType)
6474   {
6475     bool isShared = false;
6476     TopTools_MapIteratorOfMapOfShape anItr( theToCheck );
6477     for (; !isShared && anItr.More(); anItr.Next() )
6478     {
6479       const TopoDS_Shape aSubSh = anItr.Key();
6480       // check for case when concurrent dimensions are same
6481       isShared = theToFind.Contains( aSubSh );
6482       // check for sub-shape with concurrent dimension
6483       TopExp_Explorer anExp( aSubSh, theType );
6484       for ( ; !isShared && anExp.More(); anExp.Next() )
6485         isShared = theToFind.Contains( anExp.Current() );
6486     }
6487     return isShared;
6488   }
6489
6490   //-----------------------------------------------------------------------------
6491   //! check algorithms
6492   static bool checkAlgo(const SMESHDS_Hypothesis* theA1,
6493                         const SMESHDS_Hypothesis* theA2)
6494   {
6495     if ( !theA1 || !theA2 ||
6496          theA1->GetType() == SMESHDS_Hypothesis::PARAM_ALGO ||
6497          theA2->GetType() == SMESHDS_Hypothesis::PARAM_ALGO )
6498       return false; // one of the hypothesis is not algorithm
6499     // check algorithm names (should be equal)
6500     return strcmp( theA1->GetName(), theA2->GetName() ) == 0;
6501   }
6502
6503
6504   //-----------------------------------------------------------------------------
6505   //! Check if sub-shape hypotheses are concurrent
6506   bool IsConcurrent(const SMESH_DimHyp* theOther) const
6507   {
6508     if ( _subMesh == theOther->_subMesh )
6509       return false; // same sub-shape - should not be
6510
6511     // if ( <own dim of either of submeshes> == <concurrent dim> &&
6512     //      any of the two submeshes is not on COMPOUND shape )
6513     //  -> no concurrency
6514     bool meIsCompound    = (_subMesh->GetSubMeshDS() &&
6515                             _subMesh->GetSubMeshDS()->IsComplexSubmesh());
6516     bool otherIsCompound = (theOther->_subMesh->GetSubMeshDS() &&
6517                             theOther->_subMesh->GetSubMeshDS()->IsComplexSubmesh());
6518     if ( (_ownDim == _dim  || theOther->_ownDim == _dim ) && (!meIsCompound || !otherIsCompound))
6519       return false;
6520
6521     bool checkSubShape = isShareSubShapes( _shapeMap, theOther->_shapeMap, shapeTypeByDim(_dim));
6522     if ( !checkSubShape )
6523       return false;
6524
6525     // check algorithms to be same
6526     const SMESH_Algo* a1 = this->GetAlgo();
6527     const SMESH_Algo* a2 = theOther->GetAlgo();
6528     bool isSame = checkAlgo( a1, a2 );
6529     if ( !isSame )
6530     {
6531       return true;
6532       // commented off for IPAL54678
6533       // if ( !a1 || !a2 )
6534       //   return false; // pb?
6535       // return a1->GetDim() == a2->GetDim(); // different algorithms of same dim -> concurrency !
6536     }
6537
6538     // check hypothesises for concurrence (skip first as algorithm)
6539     size_t nbSame = 0;
6540     // pointers should be same, because it is referened from mesh hypothesis partition
6541     list <const SMESHDS_Hypothesis*>::const_iterator hypIt = _hypotheses.begin();
6542     list <const SMESHDS_Hypothesis*>::const_iterator otheEndIt = theOther->_hypotheses.end();
6543     for ( hypIt++ /*skip first as algo*/; hypIt != _hypotheses.end(); hypIt++ )
6544       if ( find( theOther->_hypotheses.begin(), otheEndIt, *hypIt ) != otheEndIt )
6545         nbSame++;
6546     // the submeshes are concurrent if their algorithms has different parameters
6547     return nbSame != theOther->_hypotheses.size() - 1;
6548   }
6549
6550   // Return true if algorithm of this SMESH_DimHyp is used if no
6551   // sub-mesh order is imposed by the user
6552   bool IsHigherPriorityThan( const SMESH_DimHyp* theOther ) const
6553   {
6554     // NeedDiscreteBoundary() algo has a higher priority
6555     if ( this    ->GetAlgo()->NeedDiscreteBoundary() !=
6556          theOther->GetAlgo()->NeedDiscreteBoundary() )
6557       return !this->GetAlgo()->NeedDiscreteBoundary();
6558
6559     return ( this->_subMesh->GetId() < theOther->_subMesh->GetId() );
6560   }
6561
6562 }; // end of SMESH_DimHyp
6563 //-----------------------------------------------------------------------------
6564
6565 typedef list<const SMESH_DimHyp*> TDimHypList;
6566
6567 //-----------------------------------------------------------------------------
6568
6569 void addDimHypInstance(const int                               theDim,
6570                        const TopoDS_Shape&                     theShape,
6571                        const SMESH_Algo*                       theAlgo,
6572                        const SMESH_subMesh*                    theSubMesh,
6573                        const list <const SMESHDS_Hypothesis*>& theHypList,
6574                        TDimHypList*                            theDimHypListArr )
6575 {
6576   if ( !theAlgo->NeedDiscreteBoundary() &&
6577        theAlgo->NeedLowerHyps( theDim )) // IPAL54678
6578     return;
6579   TDimHypList& listOfdimHyp = theDimHypListArr[theDim];
6580   if ( listOfdimHyp.empty() || listOfdimHyp.back()->_subMesh != theSubMesh )
6581   {
6582     SMESH_DimHyp* dimHyp = new SMESH_DimHyp( theSubMesh, theDim, theShape );
6583     dimHyp->_hypotheses.push_front(theAlgo);
6584     listOfdimHyp.push_back( dimHyp );
6585   }
6586
6587   SMESH_DimHyp* dimHyp = const_cast<SMESH_DimHyp*>( listOfdimHyp.back() );
6588   dimHyp->_hypotheses.insert( dimHyp->_hypotheses.end(),
6589                               theHypList.begin(), theHypList.end() );
6590 }
6591
6592 //-----------------------------------------------------------------------------
6593 void addInOrderOfPriority( const SMESH_DimHyp* theDimHyp,
6594                            TDimHypList&        theListOfConcurr)
6595 {
6596   if ( theListOfConcurr.empty() )
6597   {
6598     theListOfConcurr.push_back( theDimHyp );
6599   }
6600   else
6601   {
6602     TDimHypList::iterator hypIt = theListOfConcurr.begin();
6603     while ( hypIt != theListOfConcurr.end() &&
6604             !theDimHyp->IsHigherPriorityThan( *hypIt ))
6605       ++hypIt;
6606     theListOfConcurr.insert( hypIt, theDimHyp );
6607   }
6608 }
6609
6610 //-----------------------------------------------------------------------------
6611 void findConcurrents(const SMESH_DimHyp* theDimHyp,
6612                      const TDimHypList&  theListOfDimHyp,
6613                      TDimHypList&        theListOfConcurrHyp,
6614                      set<int>&           theSetOfConcurrId )
6615 {
6616   TDimHypList::const_reverse_iterator rIt = theListOfDimHyp.rbegin();
6617   for ( ; rIt != theListOfDimHyp.rend(); rIt++ )
6618   {
6619     const SMESH_DimHyp* curDimHyp = *rIt;
6620     if ( curDimHyp == theDimHyp )
6621       break; // meet own dimHyp pointer in same dimension
6622
6623     if ( theDimHyp->IsConcurrent( curDimHyp ) &&
6624          theSetOfConcurrId.insert( curDimHyp->_subMesh->GetId() ).second )
6625     {
6626       addInOrderOfPriority( curDimHyp, theListOfConcurrHyp );
6627     }
6628   }
6629 }
6630
6631 //-----------------------------------------------------------------------------
6632 void unionLists(TListOfInt&       theListOfId,
6633                 TListOfListOfInt& theListOfListOfId,
6634                 const int         theIndx )
6635 {
6636   TListOfListOfInt::iterator it = theListOfListOfId.begin();
6637   for ( int i = 0; it != theListOfListOfId.end(); it++, i++ )
6638   {
6639     if ( i < theIndx )
6640       continue; //skip already treated lists
6641     // check if other list has any same submesh object
6642     TListOfInt& otherListOfId = *it;
6643     if ( find_first_of( theListOfId.begin(), theListOfId.end(),
6644                         otherListOfId.begin(), otherListOfId.end() ) == theListOfId.end() )
6645       continue;
6646
6647     // union two lists (from source into target)
6648     TListOfInt::iterator it2 = otherListOfId.begin();
6649     for ( ; it2 != otherListOfId.end(); it2++ ) {
6650       if ( find( theListOfId.begin(), theListOfId.end(), (*it2) ) == theListOfId.end() )
6651         theListOfId.push_back(*it2);
6652     }
6653     // clear source list
6654     otherListOfId.clear();
6655   }
6656 }
6657 //-----------------------------------------------------------------------------
6658
6659 //! free memory allocated for dimension-hypothesis objects
6660 void removeDimHyps( TDimHypList* theArrOfList )
6661 {
6662   for (int i = 0; i < 4; i++ ) {
6663     TDimHypList& listOfdimHyp = theArrOfList[i];
6664     TDimHypList::const_iterator it = listOfdimHyp.begin();
6665     for ( ; it != listOfdimHyp.end(); it++ )
6666       delete (*it);
6667   }
6668 }
6669
6670 //-----------------------------------------------------------------------------
6671 /*!
6672  * \brief find common submeshes with given submesh
6673  * \param theSubMeshList list of already collected submesh to check
6674  * \param theSubMesh given submesh to intersect with other
6675  * \param theCommonSubMeshes collected common submeshes
6676  */
6677 void findCommonSubMesh (list<const SMESH_subMesh*>& theSubMeshList,
6678                         const SMESH_subMesh*        theSubMesh,
6679                         set<const SMESH_subMesh*>&  theCommon )
6680 {
6681   if ( !theSubMesh )
6682     return;
6683   list<const SMESH_subMesh*>::const_iterator it = theSubMeshList.begin();
6684   for ( ; it != theSubMeshList.end(); it++ )
6685     theSubMesh->FindIntersection( *it, theCommon );
6686   theSubMeshList.push_back( theSubMesh );
6687   //theCommon.insert( theSubMesh );
6688 }
6689
6690 //-----------------------------------------------------------------------------
6691 bool isSubMeshInList ( int smID, const TListOfListOfInt& smLists )
6692 {
6693   TListOfListOfInt::const_iterator listsIt = smLists.begin();
6694   for ( ; listsIt != smLists.end(); ++listsIt )
6695   {
6696     const TListOfInt& smIDs = *listsIt;
6697     if ( std::find( smIDs.begin(), smIDs.end(), smID ) != smIDs.end() )
6698       return true;
6699   }
6700   return false;
6701 }
6702
6703 } // namespace
6704
6705 //=============================================================================
6706 /*!
6707  * \brief Return \c true if a meshing order not yet set for a concurrent sub-mesh
6708  */
6709 //=============================================================================
6710
6711 CORBA::Boolean SMESH_Mesh_i::IsUnorderedSubMesh(CORBA::Long submeshID)
6712 {
6713   TListOfListOfInt anOrder = GetImpl().GetMeshOrder(); // already defined order
6714   if ( isSubMeshInList( submeshID, anOrder ))
6715     return false;
6716
6717   TListOfListOfInt allConurrent = findConcurrentSubMeshes();
6718   return isSubMeshInList( submeshID, allConurrent );
6719 }
6720
6721 //=============================================================================
6722 /*!
6723  * \brief Return sub-mesh objects list in meshing order
6724  */
6725 //=============================================================================
6726
6727 SMESH::submesh_array_array* SMESH_Mesh_i::GetMeshOrder()
6728 {
6729   SMESH::submesh_array_array_var aResult = new SMESH::submesh_array_array();
6730
6731   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
6732   if ( !aMeshDS )
6733     return aResult._retn();
6734
6735   TListOfListOfInt      anOrder = GetImpl().GetMeshOrder(); // already defined order
6736   TListOfListOfInt allConurrent = findConcurrentSubMeshes();
6737   anOrder.splice( anOrder.end(), allConurrent );
6738
6739   int listIndx = 0;
6740   TListOfListOfInt::iterator listIt = anOrder.begin();
6741   for(; listIt != anOrder.end(); listIt++, listIndx++ )
6742     unionLists( *listIt,  anOrder, listIndx + 1 );
6743
6744   // convert submesh ids into interface instances
6745   //  and dump command into python
6746   convertMeshOrder( anOrder, aResult, false );
6747
6748   return aResult._retn();
6749 }
6750
6751 //=============================================================================
6752 /*!
6753  * \brief Finds concurrent sub-meshes
6754  */
6755 //=============================================================================
6756
6757 TListOfListOfInt SMESH_Mesh_i::findConcurrentSubMeshes()
6758 {
6759   TListOfListOfInt anOrder;
6760   ::SMESH_Mesh& mesh = GetImpl();
6761
6762   // collect submeshes and detect concurrent algorithms and hypothesises
6763   TDimHypList dimHypListArr[4]; // dimHyp list for each shape dimension
6764
6765   map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
6766   for ( ; i_sm != _mapSubMesh.end(); i_sm++ )
6767   {
6768     ::SMESH_subMesh* sm = (*i_sm).second;
6769     // shape of submesh
6770     const TopoDS_Shape& aSubMeshShape = sm->GetSubShape();
6771
6772     // list of assigned hypothesises
6773     const list <const SMESHDS_Hypothesis*>& hypList = mesh.GetHypothesisList(aSubMeshShape);
6774     // Find out dimensions where the submesh can be concurrent.
6775     // We define the dimensions by algo of each of hypotheses in hypList
6776     list <const SMESHDS_Hypothesis*>::const_iterator hypIt = hypList.begin();
6777     for( ; hypIt != hypList.end(); hypIt++ )
6778     {
6779       SMESH_Algo* anAlgo = 0;
6780       const SMESH_Hypothesis* hyp = dynamic_cast<const SMESH_Hypothesis*>(*hypIt);
6781       if ( hyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO )
6782         // hyp it-self is algo
6783         anAlgo = (SMESH_Algo*)dynamic_cast<const SMESH_Algo*>(hyp);
6784       else {
6785         // try to find algorithm with help of sub-shapes
6786         TopExp_Explorer anExp( aSubMeshShape, shapeTypeByDim(hyp->GetDim()) );
6787         for ( ; !anAlgo && anExp.More(); anExp.Next() )
6788           anAlgo = mesh.GetGen()->GetAlgo( mesh, anExp.Current() );
6789       }
6790       if (!anAlgo)
6791         continue; // no algorithm assigned to a current submesh
6792
6793       int dim = anAlgo->GetDim(); // top concurrent dimension (see comment to SMESH_DimHyp)
6794       // the submesh can concurrent at <dim> (or lower dims if !anAlgo->NeedDiscreteBoundary()
6795       // and !anAlgo->NeedLowerHyps( dim ))
6796
6797       // create instance of dimension-hypothesis for found concurrent dimension(s) and algorithm
6798       for ( int j = anAlgo->NeedDiscreteBoundary() ? dim : 1, jn = dim; j <= jn; j++ )
6799         addDimHypInstance( j, aSubMeshShape, anAlgo, sm, hypList, dimHypListArr );
6800     }
6801   } // end iterations on submesh
6802
6803     // iterate on created dimension-hypotheses and check for concurrents
6804   for ( int i = 0; i < 4; i++ )
6805   {
6806     const TDimHypList& listOfDimHyp = dimHypListArr[i];
6807     // check for concurrents in own and other dimensions (step-by-step)
6808     TDimHypList::const_iterator dhIt = listOfDimHyp.begin();
6809     for ( ; dhIt != listOfDimHyp.end(); dhIt++ )
6810     {
6811       const SMESH_DimHyp* dimHyp = *dhIt;
6812       TDimHypList listOfConcurr;
6813       set<int>    setOfConcurrIds;
6814       // looking for concurrents and collect into own list
6815       for ( int j = i; j < 4; j++ )
6816         findConcurrents( dimHyp, dimHypListArr[j], listOfConcurr, setOfConcurrIds );
6817       // check if any concurrents found
6818       if ( listOfConcurr.size() > 0 )
6819       {
6820         // add own submesh to list of concurrent
6821         addInOrderOfPriority( dimHyp, listOfConcurr );
6822         list<int> listOfConcurrIds;
6823         TDimHypList::iterator hypIt = listOfConcurr.begin();
6824         for ( ; hypIt != listOfConcurr.end(); ++hypIt )
6825           listOfConcurrIds.push_back( (*hypIt)->_subMesh->GetId() );
6826         anOrder.push_back( listOfConcurrIds );
6827       }
6828     }
6829   }
6830
6831   removeDimHyps(dimHypListArr);
6832
6833   // now, minimize the number of concurrent groups
6834   // Here we assume that lists of submeshes can have same submesh
6835   // in case of multi-dimension algorithms, as result
6836   //  list with common submesh has to be united into one list
6837   int listIndx = 0;
6838   TListOfListOfInt::iterator listIt = anOrder.begin();
6839   for(; listIt != anOrder.end(); listIt++, listIndx++ )
6840     unionLists( *listIt,  anOrder, listIndx + 1 );
6841
6842   return anOrder;
6843 }
6844
6845 //=============================================================================
6846 /*!
6847  * \brief Set submesh object order
6848  * \param theSubMeshArray submesh array order
6849  */
6850 //=============================================================================
6851
6852 ::CORBA::Boolean SMESH_Mesh_i::SetMeshOrder(const SMESH::submesh_array_array& theSubMeshArray)
6853 {
6854   if ( _preMeshInfo )
6855     _preMeshInfo->ForgetOrLoad();
6856
6857   bool res = false;
6858   ::SMESH_Mesh& mesh = GetImpl();
6859
6860   TPythonDump aPythonDump; // prevent dump of called methods
6861   aPythonDump << "isDone = " << SMESH::SMESH_Mesh_var(_this()) << ".SetMeshOrder( [ ";
6862
6863   TListOfListOfInt subMeshOrder;
6864   for ( int i = 0, n = theSubMeshArray.length(); i < n; i++ )
6865   {
6866     const SMESH::submesh_array& aSMArray = theSubMeshArray[i];
6867     TListOfInt subMeshIds;
6868     if ( i > 0 )
6869       aPythonDump << ", ";
6870     aPythonDump << "[ ";
6871     // Collect subMeshes which should be clear
6872     //  do it list-by-list, because modification of submesh order
6873     //  take effect between concurrent submeshes only
6874     set<const SMESH_subMesh*> subMeshToClear;
6875     list<const SMESH_subMesh*> subMeshList;
6876     for ( int j = 0, jn = aSMArray.length(); j < jn; j++ )
6877     {
6878       const SMESH::SMESH_subMesh_var subMesh = SMESH::SMESH_subMesh::_duplicate(aSMArray[j]);
6879       if ( j > 0 )
6880         aPythonDump << ", ";
6881       aPythonDump << subMesh;
6882       subMeshIds.push_back( subMesh->GetId() );
6883       // detect common parts of submeshes
6884       if ( _mapSubMesh.find(subMesh->GetId()) != _mapSubMesh.end() )
6885         findCommonSubMesh( subMeshList, _mapSubMesh[ subMesh->GetId() ], subMeshToClear );
6886     }
6887     aPythonDump << " ]";
6888     subMeshOrder.push_back( subMeshIds );
6889
6890     // clear collected sub-meshes
6891     set<const SMESH_subMesh*>::iterator clrIt = subMeshToClear.begin();
6892     for ( ; clrIt != subMeshToClear.end(); clrIt++ )
6893       if ( SMESH_subMesh* sm = (SMESH_subMesh*)*clrIt )
6894       {
6895         sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
6896         if ( SMESH_Algo* algo = sm->GetAlgo() ) // #16748
6897           sm->AlgoStateEngine( SMESH_subMesh::MODIF_HYP, algo ); // to clear a cached algo
6898       }
6899   }
6900   aPythonDump << " ])";
6901
6902   mesh.SetMeshOrder( subMeshOrder );
6903   res = true;
6904
6905   SMESH::SMESH_Mesh_var me = _this();
6906   _gen_i->UpdateIcons( me );
6907
6908   return res;
6909 }
6910
6911 //=============================================================================
6912 /*!
6913  * \brief Convert submesh ids into submesh interfaces
6914  */
6915 //=============================================================================
6916
6917 void SMESH_Mesh_i::convertMeshOrder (const TListOfListOfInt&     theIdsOrder,
6918                                      SMESH::submesh_array_array& theResOrder,
6919                                      const bool                  theIsDump)
6920 {
6921   int nbSet = theIdsOrder.size();
6922   TPythonDump aPythonDump; // prevent dump of called methods
6923   if ( theIsDump )
6924     aPythonDump << "[ ";
6925   theResOrder.length(nbSet);
6926   TListOfListOfInt::const_iterator it = theIdsOrder.begin();
6927   int listIndx = 0;
6928   for( ; it != theIdsOrder.end(); it++ )
6929   {
6930     // translate submesh identificators into submesh objects
6931     //  takeing into account real number of concurrent lists
6932     const TListOfInt& aSubOrder = (*it);
6933     if (!aSubOrder.size())
6934       continue;
6935     if ( theIsDump )
6936       aPythonDump << "[ ";
6937     // convert shape indices into interfaces
6938     SMESH::submesh_array_var aResSubSet = new SMESH::submesh_array();
6939     aResSubSet->length(aSubOrder.size());
6940     TListOfInt::const_iterator subIt = aSubOrder.begin();
6941     int j;
6942     for( j = 0; subIt != aSubOrder.end(); subIt++ )
6943     {
6944       if ( _mapSubMeshIor.find(*subIt) == _mapSubMeshIor.end() )
6945         continue;
6946       SMESH::SMESH_subMesh_var subMesh =
6947         SMESH::SMESH_subMesh::_duplicate( _mapSubMeshIor[*subIt] );
6948       if ( theIsDump ) {
6949         if ( j > 0 )
6950           aPythonDump << ", ";
6951         aPythonDump << subMesh;
6952       }
6953       aResSubSet[ j++ ] = subMesh;
6954     }
6955     if ( theIsDump )
6956       aPythonDump << " ]";
6957     if ( j > 1 )
6958       theResOrder[ listIndx++ ] = aResSubSet;
6959   }
6960   // correct number of lists
6961   theResOrder.length( listIndx );
6962
6963   if ( theIsDump ) {
6964     // finilise python dump
6965     aPythonDump << " ]";
6966     aPythonDump << " = " << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshOrder()";
6967   }
6968 }
6969
6970 namespace // utils used by SMESH_MeshPartDS
6971 {
6972   /*!
6973    * \brief Class used to access to protected data of SMDS_MeshInfo
6974    */
6975   struct TMeshInfo : public SMDS_MeshInfo
6976   {
6977     void Add(const SMDS_MeshElement* e) { SMDS_MeshInfo::addWithPoly( e ); }
6978   };
6979   /*!
6980    * \brief Element holing its ID only
6981    */
6982   struct TElemID : public SMDS_LinearEdge
6983   {
6984     TElemID(int ID) : SMDS_LinearEdge(0,0) { setID( ID ); }
6985   };
6986 }
6987
6988 //================================================================================
6989 //
6990 // Implementation of SMESH_MeshPartDS
6991 //
6992 SMESH_MeshPartDS::SMESH_MeshPartDS(SMESH::SMESH_IDSource_ptr meshPart):
6993   SMESHDS_Mesh( /*meshID=*/-1, /*isEmbeddedMode=*/true)
6994 {
6995   SMESH::SMESH_Mesh_var mesh = meshPart->GetMesh();
6996   SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
6997
6998   mesh_i->Load();
6999   _meshDS = mesh_i->GetImpl().GetMeshDS();
7000
7001   SetPersistentId( _meshDS->GetPersistentId() );
7002
7003   if ( mesh_i == SMESH::DownCast<SMESH_Mesh_i*>( meshPart ))
7004   {
7005     // <meshPart> is the whole mesh
7006     myInfo = _meshDS->GetMeshInfo(); // copy mesh info;
7007     // copy groups
7008     set<SMESHDS_GroupBase*>& myGroupSet = const_cast<set<SMESHDS_GroupBase*>&>( GetGroups() );
7009     myGroupSet = _meshDS->GetGroups();
7010   }
7011   else
7012   {
7013     TMeshInfo tmpInfo;
7014     SMESH::long_array_var           anIDs = meshPart->GetIDs();
7015     SMESH::array_of_ElementType_var types = meshPart->GetTypes();
7016     if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
7017     {
7018       for ( CORBA::ULong i=0; i < anIDs->length(); i++ )
7019         if ( const SMDS_MeshNode * n = _meshDS->FindNode( anIDs[i] ))
7020           if ( _elements[ SMDSAbs_Node ].insert( n ).second )
7021             tmpInfo.Add( n );
7022     }
7023     else
7024     {
7025       for ( CORBA::ULong i=0; i < anIDs->length(); i++ )
7026         if ( const SMDS_MeshElement * e = _meshDS->FindElement(anIDs[i]))
7027           if ( _elements[ e->GetType() ].insert( e ).second )
7028           {
7029             tmpInfo.Add( e );
7030             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7031             while ( nIt->more() )
7032             {
7033               const SMDS_MeshNode * n = (const SMDS_MeshNode*) nIt->next();
7034               if ( _elements[ SMDSAbs_Node ].insert( n ).second )
7035                 tmpInfo.Add( n );
7036             }
7037           }
7038     }
7039     myInfo = tmpInfo;
7040
7041     ShapeToMesh( _meshDS->ShapeToMesh() );
7042
7043     _meshDS = 0; // to enforce iteration on _elements and _nodes
7044   }
7045 }
7046 // -------------------------------------------------------------------------------------
7047 SMESH_MeshPartDS::SMESH_MeshPartDS(const std::list< const SMDS_MeshElement* > & meshPart):
7048   SMESHDS_Mesh( /*meshID=*/-1, /*isEmbeddedMode=*/true), _meshDS(0)
7049 {
7050   TMeshInfo tmpInfo;
7051   list< const SMDS_MeshElement* >::const_iterator partIt = meshPart.begin();
7052   for ( ; partIt != meshPart.end(); ++partIt )
7053     if ( const SMDS_MeshElement * e = *partIt )
7054       if ( _elements[ e->GetType() ].insert( e ).second )
7055       {
7056         tmpInfo.Add( e );
7057         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7058         while ( nIt->more() )
7059         {
7060           const SMDS_MeshNode * n = (const SMDS_MeshNode*) nIt->next();
7061           if ( _elements[ SMDSAbs_Node ].insert( n ).second )
7062             tmpInfo.Add( n );
7063         }
7064       }
7065   myInfo = tmpInfo;
7066 }
7067 // -------------------------------------------------------------------------------------
7068 const SMDS_MeshElement * SMESH_MeshPartDS::FindElement(int IDelem) const
7069 {
7070   if ( _meshDS ) return _meshDS->FindElement( IDelem );
7071
7072   TElemID elem( IDelem );
7073   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
7074     if ( !_elements[ iType ].empty() )
7075     {
7076       TIDSortedElemSet::const_iterator it = _elements[ iType ].find( &elem );
7077       if ( it != _elements[ iType ].end() )
7078         return *it;
7079     }
7080   return 0;
7081 }
7082 // -------------------------------------------------------------------------------------
7083 bool SMESH_MeshPartDS::HasNumerationHoles()
7084 {
7085   if ( _meshDS ) return _meshDS->HasNumerationHoles();
7086
7087   return ( MinNodeID() != 1 ||
7088            MaxNodeID() != NbNodes() ||
7089            MinElementID() != 1 ||
7090            MaxElementID() != NbElements() );
7091 }
7092 // -------------------------------------------------------------------------------------
7093 int SMESH_MeshPartDS::MaxNodeID() const
7094 {
7095   if ( _meshDS ) return _meshDS->MaxNodeID();
7096   return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].rbegin())->GetID();
7097 }
7098 // -------------------------------------------------------------------------------------
7099 int SMESH_MeshPartDS::MinNodeID() const
7100 {
7101   if ( _meshDS ) return _meshDS->MinNodeID();
7102   return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].begin())->GetID();
7103 }  
7104 // -------------------------------------------------------------------------------------
7105 int SMESH_MeshPartDS::MaxElementID() const
7106 {
7107   if ( _meshDS ) return _meshDS->MaxElementID();
7108   int maxID = 0;
7109   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
7110     if ( !_elements[ iType ].empty() )
7111       maxID = Max( maxID, (*_elements[ iType ].rbegin())->GetID() );
7112   return maxID;
7113 }
7114 // -------------------------------------------------------------------------------------
7115 int SMESH_MeshPartDS::MinElementID() const
7116 {
7117   if ( _meshDS ) return _meshDS->MinElementID();
7118   int minID = 0;
7119   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
7120     if ( !_elements[ iType ].empty() )
7121       minID = Min( minID, (*_elements[ iType ].begin())->GetID() );
7122   return minID;
7123 }
7124 // -------------------------------------------------------------------------------------
7125 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementGeomIterator(SMDSAbs_GeometryType geomType) const
7126 {
7127   if ( _meshDS ) return _meshDS->elementGeomIterator( geomType );
7128
7129   typedef SMDS_SetIterator
7130     <const SMDS_MeshElement*,
7131     TIDSortedElemSet::const_iterator,
7132     SMDS::SimpleAccessor<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator>,
7133     SMDS_MeshElement::GeomFilter
7134     > TIter;
7135
7136   SMDSAbs_ElementType type = SMDS_MeshCell::ElemType( geomType );
7137
7138   return SMDS_ElemIteratorPtr( new TIter( _elements[type].begin(),
7139                                           _elements[type].end(),
7140                                           SMDS_MeshElement::GeomFilter( geomType )));
7141 }
7142 // -------------------------------------------------------------------------------------
7143 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementEntityIterator(SMDSAbs_EntityType entity) const
7144 {
7145   if ( _meshDS ) return _meshDS->elementEntityIterator( entity );
7146
7147   typedef SMDS_SetIterator
7148     <const SMDS_MeshElement*,
7149     TIDSortedElemSet::const_iterator,
7150     SMDS::SimpleAccessor<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator>,
7151     SMDS_MeshElement::EntityFilter
7152     > TIter;
7153
7154   SMDSAbs_ElementType type = SMDS_MeshCell::ElemType( entity );
7155
7156   return SMDS_ElemIteratorPtr( new TIter( _elements[type].begin(),
7157                                           _elements[type].end(),
7158                                           SMDS_MeshElement::EntityFilter( entity )));
7159 }
7160 // -------------------------------------------------------------------------------------
7161 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementsIterator(SMDSAbs_ElementType type) const
7162 {
7163   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
7164   if ( type == SMDSAbs_All && !_meshDS )
7165   {
7166     typedef vector< SMDS_ElemIteratorPtr > TIterVec;
7167     TIterVec iterVec;
7168     for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
7169       if ( !_elements[i].empty() && i != SMDSAbs_Node )
7170         iterVec.push_back
7171           ( SMDS_ElemIteratorPtr( new TIter( _elements[i].begin(), _elements[i].end() )));
7172
7173     typedef SMDS_IteratorOnIterators<const SMDS_MeshElement*, TIterVec > TIterOnIters;
7174     return SMDS_ElemIteratorPtr( new TIterOnIters( iterVec ));
7175   }
7176   return _meshDS ? _meshDS->elementsIterator(type) : SMDS_ElemIteratorPtr
7177       ( new TIter( _elements[type].begin(), _elements[type].end() ));
7178 }
7179 // -------------------------------------------------------------------------------------
7180 #define _GET_ITER_DEFINE( iterType, methName, elem, elemType)                       \
7181   iterType SMESH_MeshPartDS::methName() const                 \
7182   {                                                                                 \
7183     typedef SMDS_SetIterator<const elem*, TIDSortedElemSet::const_iterator > TIter; \
7184     return _meshDS ? _meshDS->methName() : iterType                 \
7185       ( new TIter( _elements[elemType].begin(), _elements[elemType].end() ));       \
7186   }
7187 // -------------------------------------------------------------------------------------
7188 _GET_ITER_DEFINE( SMDS_NodeIteratorPtr, nodesIterator, SMDS_MeshNode, SMDSAbs_Node )
7189 _GET_ITER_DEFINE( SMDS_EdgeIteratorPtr, edgesIterator, SMDS_MeshEdge, SMDSAbs_Edge )
7190 _GET_ITER_DEFINE( SMDS_FaceIteratorPtr, facesIterator, SMDS_MeshFace, SMDSAbs_Face )
7191 _GET_ITER_DEFINE( SMDS_VolumeIteratorPtr, volumesIterator, SMDS_MeshVolume, SMDSAbs_Volume)
7192 #undef _GET_ITER_DEFINE
7193 //
7194 // END Implementation of SMESH_MeshPartDS
7195 //
7196 //================================================================================