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