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