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