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