Salome HOME
Fix compilation errors under Windows: VS-2017
[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     void RemoveGroup (const int theGroupID) override { _mesh->removeGroup( theGroupID ); }
3439     void HypothesisModified( int hypID,
3440                              bool updIcons) override { _mesh->onHypothesisModified( hypID,
3441                                                                                     updIcons ); }
3442     void Load ()                            override { _mesh->Load(); }
3443     bool IsLoaded()                         override { return _mesh->IsLoaded(); }
3444     TopoDS_Shape GetShapeByEntry(const std::string& entry) override
3445     {
3446       GEOM::GEOM_Object_var go = SMESH_Gen_i::GetGeomObjectByEntry( entry );
3447       return SMESH_Gen_i::GeomObjectToShape( go );
3448     }
3449   };
3450 }
3451
3452 //================================================================================
3453 /*!
3454  * \brief callback from _impl to
3455  *     1) forget not loaded mesh data (issue 0021208)
3456  *     2) mark hypothesis as valid
3457  */
3458 //================================================================================
3459
3460 void SMESH_Mesh_i::onHypothesisModified(int theHypID, bool theUpdateIcons)
3461 {
3462   if ( _preMeshInfo )
3463     _preMeshInfo->ForgetOrLoad();
3464
3465   if ( theUpdateIcons )
3466   {
3467     SMESH::SMESH_Mesh_var mesh = _this();
3468     _gen_i->UpdateIcons( mesh );
3469   }
3470
3471   if ( _nbInvalidHypos != 0 )
3472   {
3473     // mark a hypothesis as valid after edition
3474     int nbInvalid = 0;
3475     SALOMEDS::SComponent_wrap smeshComp = _gen_i->PublishComponent();
3476     SALOMEDS::SObject_wrap hypRoot;
3477     if ( !smeshComp->_is_nil() &&
3478          smeshComp->FindSubObject( _gen_i->GetHypothesisRootTag(), hypRoot.inout() ))
3479     {
3480       SALOMEDS::ChildIterator_wrap anIter = _gen_i->getStudyServant()->NewChildIterator( hypRoot );
3481       for ( ; anIter->More(); anIter->Next() )
3482       {
3483         SALOMEDS::SObject_wrap    hypSO = anIter->Value();
3484         CORBA::Object_var           obj = _gen_i->SObjectToObject( hypSO );
3485         SMESH::SMESH_Hypothesis_var hyp = SMESH::SMESH_Hypothesis::_narrow( obj );
3486         if ( !hyp->_is_nil() && hyp->GetId() == theHypID )
3487           _gen_i->HighLightInvalid( hyp, false );
3488         else
3489           nbInvalid += _gen_i->IsInvalid( hypSO );
3490       }
3491     }
3492     _nbInvalidHypos = nbInvalid;
3493   }
3494 }
3495
3496 //================================================================================
3497 /*!
3498  * \brief Set mesh implementation
3499  */
3500 //================================================================================
3501
3502 void SMESH_Mesh_i::SetImpl(::SMESH_Mesh * impl)
3503 {
3504   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::SetImpl");
3505   _impl = impl;
3506   if ( _impl )
3507     _impl->SetCallUp( new TCallUp_i(this));
3508 }
3509
3510 //=============================================================================
3511 /*!
3512  * Return a mesh implementation
3513  */
3514 //=============================================================================
3515
3516 ::SMESH_Mesh & SMESH_Mesh_i::GetImpl()
3517 {
3518   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::GetImpl()");
3519   return *_impl;
3520 }
3521
3522 //=============================================================================
3523 /*!
3524  * Return mesh editor
3525  */
3526 //=============================================================================
3527
3528 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditor()
3529   throw (SALOME::SALOME_Exception)
3530 {
3531   SMESH::SMESH_MeshEditor_var aMeshEdVar;
3532
3533   SMESH_TRY;
3534   if ( _preMeshInfo )
3535     _preMeshInfo->FullLoadFromFile();
3536
3537   // Create MeshEditor
3538   if ( !_editor )
3539     _editor = new SMESH_MeshEditor_i( this, false );
3540   aMeshEdVar = _editor->_this();
3541
3542   // Update Python script
3543   TPythonDump() << _editor << " = "
3544                 << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshEditor()";
3545
3546   SMESH_CATCH( SMESH::throwCorbaException );
3547
3548   return aMeshEdVar._retn();
3549 }
3550
3551 //=============================================================================
3552 /*!
3553  * Return mesh edition previewer
3554  */
3555 //=============================================================================
3556
3557 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditPreviewer()
3558   throw (SALOME::SALOME_Exception)
3559 {
3560   SMESH::SMESH_MeshEditor_var aMeshEdVar;
3561
3562   SMESH_TRY;
3563   if ( _preMeshInfo )
3564     _preMeshInfo->FullLoadFromFile();
3565
3566   if ( !_previewEditor )
3567     _previewEditor = new SMESH_MeshEditor_i( this, true );
3568   aMeshEdVar = _previewEditor->_this();
3569
3570   SMESH_CATCH( SMESH::throwCorbaException );
3571
3572   return aMeshEdVar._retn();
3573 }
3574
3575 //================================================================================
3576 /*!
3577  * \brief Return true if the mesh has been edited since a last total re-compute
3578  *        and those modifications may prevent successful partial re-compute
3579  */
3580 //================================================================================
3581
3582 CORBA::Boolean SMESH_Mesh_i::HasModificationsToDiscard() throw(SALOME::SALOME_Exception)
3583 {
3584   Unexpect aCatch(SALOME_SalomeException);
3585   return _impl->HasModificationsToDiscard();
3586 }
3587
3588 //================================================================================
3589 /*!
3590  * \brief Return a random unique color
3591  */
3592 //================================================================================
3593
3594 static SALOMEDS::Color getUniqueColor( const std::list<SALOMEDS::Color>& theReservedColors )
3595 {
3596   const int MAX_ATTEMPTS = 100;
3597   int cnt = 0;
3598   double tolerance = 0.5;
3599   SALOMEDS::Color col;
3600
3601   bool ok = false;
3602   while ( !ok ) {
3603     // generate random color
3604     double red    = (double)rand() / RAND_MAX;
3605     double green  = (double)rand() / RAND_MAX;
3606     double blue   = (double)rand() / RAND_MAX;
3607     // check existence in the list of the existing colors
3608     bool matched = false;
3609     std::list<SALOMEDS::Color>::const_iterator it;
3610     for ( it = theReservedColors.begin(); it != theReservedColors.end() && !matched; ++it ) {
3611       SALOMEDS::Color color = *it;
3612       double tol = fabs( color.R - red ) + fabs( color.G - green ) + fabs( color.B  - blue  );
3613       matched = tol < tolerance;
3614     }
3615     if ( (cnt+1) % 20 == 0 ) tolerance = tolerance/2;
3616     ok = ( ++cnt == MAX_ATTEMPTS ) || !matched;
3617     col.R = red;
3618     col.G = green;
3619     col.B = blue;
3620   }
3621   return col;
3622 }
3623
3624 //=============================================================================
3625 /*!
3626  * Set auto-color mode. If it is on, groups get unique random colors
3627  */
3628 //=============================================================================
3629
3630 void SMESH_Mesh_i::SetAutoColor(CORBA::Boolean theAutoColor) throw(SALOME::SALOME_Exception)
3631 {
3632   Unexpect aCatch(SALOME_SalomeException);
3633   _impl->SetAutoColor(theAutoColor);
3634
3635   TPythonDump pyDump; // not to dump group->SetColor() from below code
3636   pyDump << SMESH::SMESH_Mesh_var(_this()) <<".SetAutoColor( "<<theAutoColor<<" )";
3637
3638   std::list<SALOMEDS::Color> aReservedColors;
3639   map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.begin();
3640   for ( ; it != _mapGroups.end(); it++ ) {
3641     if ( CORBA::is_nil( it->second )) continue;
3642     SALOMEDS::Color aColor = getUniqueColor( aReservedColors );
3643     it->second->SetColor( aColor );
3644     aReservedColors.push_back( aColor );
3645   }
3646 }
3647
3648 //=============================================================================
3649 /*!
3650  * Return true if auto-color mode is on
3651  */
3652 //=============================================================================
3653
3654 CORBA::Boolean SMESH_Mesh_i::GetAutoColor() throw(SALOME::SALOME_Exception)
3655 {
3656   Unexpect aCatch(SALOME_SalomeException);
3657   return _impl->GetAutoColor();
3658 }
3659
3660 //=============================================================================
3661 /*!
3662  *  Check if there are groups with equal names
3663  */
3664 //=============================================================================
3665
3666 CORBA::Boolean SMESH_Mesh_i::HasDuplicatedGroupNamesMED()
3667 {
3668   return _impl->HasDuplicatedGroupNamesMED();
3669 }
3670
3671 //================================================================================
3672 /*!
3673  * \brief Care of a file before exporting mesh into it
3674  */
3675 //================================================================================
3676
3677 void SMESH_Mesh_i::PrepareForWriting (const char* file, bool overwrite)
3678 {
3679   SMESH_File aFile( file, false );
3680   SMESH_Comment msg;
3681   if ( aFile.exists() ) {
3682     // existing filesystem node
3683     if ( !aFile.isDirectory() ) {
3684       if ( aFile.openForWriting() ) {
3685         if ( overwrite && ! aFile.remove()) {
3686           msg << "Can't replace " << aFile.getName();
3687         }
3688       } else {
3689         msg << "Can't write into " << aFile.getName();
3690       }
3691     } else {
3692       msg << "Location " << aFile.getName() << " is not a file";
3693     }
3694   }
3695   else {
3696     // nonexisting file; check if it can be created
3697     if ( !aFile.openForWriting() ) {
3698       msg << "You cannot create the file "
3699           << aFile.getName()
3700           << ". Check the directory existence and access rights";
3701     }
3702     aFile.remove();
3703   }
3704
3705   if ( !msg.empty() )
3706   {
3707     msg << ".";
3708     THROW_SALOME_CORBA_EXCEPTION(msg.c_str(), SALOME::BAD_PARAM);
3709   }
3710 }
3711
3712 //================================================================================
3713 /*!
3714  * \brief Prepare a file for export and pass names of mesh groups from study to mesh DS
3715  *  \param file - file name
3716  *  \param overwrite - to erase the file or not
3717  *  \retval string - mesh name
3718  */
3719 //================================================================================
3720
3721 string SMESH_Mesh_i::prepareMeshNameAndGroups(const char*    file,
3722                                               CORBA::Boolean overwrite)
3723 {
3724   // Perform Export
3725   PrepareForWriting(file, overwrite);
3726   string aMeshName = "Mesh";
3727   SALOMEDS::Study_var aStudy = SMESH_Gen_i::getStudyServant();
3728   if ( !aStudy->_is_nil() ) {
3729     SALOMEDS::SObject_wrap aMeshSO = _gen_i->ObjectToSObject(  _this() );
3730     if ( !aMeshSO->_is_nil() ) {
3731       CORBA::String_var name = aMeshSO->GetName();
3732       aMeshName = name;
3733       // asv : 27.10.04 : fix of 6903: check for StudyLocked before adding attributes
3734       if ( !aStudy->GetProperties()->IsLocked() )
3735       {
3736         SALOMEDS::GenericAttribute_wrap anAttr;
3737         SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder();
3738         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeExternalFileDef");
3739         SALOMEDS::AttributeExternalFileDef_wrap aFileName = anAttr;
3740         ASSERT(!aFileName->_is_nil());
3741         aFileName->SetValue(file);
3742         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeFileType");
3743         SALOMEDS::AttributeFileType_wrap aFileType = anAttr;
3744         ASSERT(!aFileType->_is_nil());
3745         aFileType->SetValue("FICHIERMED");
3746       }
3747     }
3748   }
3749   // Update Python script
3750   // set name of mesh before export
3751   TPythonDump() << _gen_i << ".SetName("
3752                 << SMESH::SMESH_Mesh_var(_this()) << ", '" << aMeshName.c_str() << "')";
3753
3754   // check names of groups
3755   checkGroupNames();
3756
3757   return aMeshName;
3758 }
3759
3760 //================================================================================
3761 /*!
3762  * \brief Export to MED file
3763  */
3764 //================================================================================
3765
3766 void SMESH_Mesh_i::ExportMED(const char*        file,
3767                              CORBA::Boolean     auto_groups,
3768                              CORBA::Long        version,
3769                              CORBA::Boolean     overwrite,
3770                              CORBA::Boolean     autoDimension)
3771   throw(SALOME::SALOME_Exception)
3772 {
3773   //MESSAGE("MED minor version: "<< minor);
3774   SMESH_TRY;
3775   if ( _preMeshInfo )
3776     _preMeshInfo->FullLoadFromFile();
3777
3778   string aMeshName = prepareMeshNameAndGroups(file, overwrite);
3779   _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version, 0, autoDimension );
3780
3781   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportMED( r'"
3782                 << file << "', "
3783                 << "auto_groups=" <<auto_groups << ", "
3784                 << "version=" << version <<  ", "
3785                 << "overwrite=" << overwrite << ", "
3786                 << "meshPart=None, "
3787                 << "autoDimension=" << autoDimension << " )";
3788
3789   SMESH_CATCH( SMESH::throwCorbaException );
3790 }
3791
3792 //================================================================================
3793 /*!
3794  * \brief Export a mesh to a SAUV file
3795  */
3796 //================================================================================
3797
3798 void SMESH_Mesh_i::ExportSAUV (const char* file,
3799                                CORBA::Boolean auto_groups)
3800   throw(SALOME::SALOME_Exception)
3801 {
3802   Unexpect aCatch(SALOME_SalomeException);
3803   if ( _preMeshInfo )
3804     _preMeshInfo->FullLoadFromFile();
3805
3806   string aMeshName = prepareMeshNameAndGroups(file, true);
3807   TPythonDump() << SMESH::SMESH_Mesh_var( _this())
3808                 << ".ExportSAUV( r'" << file << "', " << auto_groups << " )";
3809   _impl->ExportSAUV(file, aMeshName.c_str(), auto_groups);
3810 }
3811
3812
3813 //================================================================================
3814 /*!
3815  * \brief Export a mesh to a DAT file
3816  */
3817 //================================================================================
3818
3819 void SMESH_Mesh_i::ExportDAT (const char *file)
3820   throw(SALOME::SALOME_Exception)
3821 {
3822   Unexpect aCatch(SALOME_SalomeException);
3823   if ( _preMeshInfo )
3824     _preMeshInfo->FullLoadFromFile();
3825
3826   // Update Python script
3827   // check names of groups
3828   checkGroupNames();
3829   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportDAT( r'" << file << "' )";
3830
3831   // Perform Export
3832   PrepareForWriting(file);
3833   _impl->ExportDAT(file);
3834 }
3835
3836 //================================================================================
3837 /*!
3838  * \brief Export a mesh to an UNV file
3839  */
3840 //================================================================================
3841
3842 void SMESH_Mesh_i::ExportUNV (const char *file)
3843   throw(SALOME::SALOME_Exception)
3844 {
3845   Unexpect aCatch(SALOME_SalomeException);
3846   if ( _preMeshInfo )
3847     _preMeshInfo->FullLoadFromFile();
3848
3849   // Update Python script
3850   // check names of groups
3851   checkGroupNames();
3852   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportUNV( r'" << file << "' )";
3853
3854   // Perform Export
3855   PrepareForWriting(file);
3856   _impl->ExportUNV(file);
3857 }
3858
3859 //================================================================================
3860 /*!
3861  * \brief Export a mesh to an STL file
3862  */
3863 //================================================================================
3864
3865 void SMESH_Mesh_i::ExportSTL (const char *file, const bool isascii)
3866   throw(SALOME::SALOME_Exception)
3867 {
3868   Unexpect aCatch(SALOME_SalomeException);
3869   if ( _preMeshInfo )
3870     _preMeshInfo->FullLoadFromFile();
3871
3872   // Update Python script
3873   // check names of groups
3874   checkGroupNames();
3875   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
3876                 << ".ExportSTL( r'" << file << "', " << isascii << " )";
3877
3878   CORBA::String_var name;
3879   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( _this() );
3880   if ( !so->_is_nil() )
3881     name = so->GetName();
3882
3883   // Perform Export
3884   PrepareForWriting( file );
3885   _impl->ExportSTL( file, isascii, name.in() );
3886 }
3887
3888 //================================================================================
3889 /*!
3890  * \brief Export a part of mesh to a med file
3891  */
3892 //================================================================================
3893
3894 void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
3895                                    const char*               file,
3896                                    CORBA::Boolean            auto_groups,
3897                                    CORBA::Long               version,
3898                                    CORBA::Boolean            overwrite,
3899                                    CORBA::Boolean            autoDimension,
3900                                    const GEOM::ListOfFields& fields,
3901                                    const char*               geomAssocFields,
3902                                    CORBA::Double             ZTolerance)
3903   throw (SALOME::SALOME_Exception)
3904 {
3905   MESSAGE("MED version: "<< version);
3906   SMESH_TRY;
3907   if ( _preMeshInfo )
3908     _preMeshInfo->FullLoadFromFile();
3909
3910   // check fields
3911   bool have0dField = false;
3912   if ( fields.length() > 0 )
3913   {
3914     GEOM::GEOM_Object_var shapeToMesh = GetShapeToMesh();
3915     if ( shapeToMesh->_is_nil() )
3916       THROW_SALOME_CORBA_EXCEPTION( "No shape to mesh", SALOME::INTERNAL_ERROR );
3917
3918     for ( size_t i = 0; i < fields.length(); ++i )
3919     {
3920       if ( fields[i]->GetDataType() == GEOM::FDT_String )
3921         THROW_SALOME_CORBA_EXCEPTION
3922           ( "Export of string fields is not supported", SALOME::BAD_PARAM);
3923       GEOM::GEOM_Object_var fieldShape = fields[i]->GetShape();
3924       if ( fieldShape->_is_nil() )
3925         THROW_SALOME_CORBA_EXCEPTION( "Null shape under a field", SALOME::INTERNAL_ERROR );
3926       if ( !fieldShape->IsSame( shapeToMesh ) )
3927         THROW_SALOME_CORBA_EXCEPTION
3928           ( "Field defined not on shape", SALOME::BAD_PARAM);
3929       if ( fields[i]->GetDimension() == 0 )
3930         have0dField = true;
3931     }
3932     if ( geomAssocFields )
3933       for ( int i = 0; geomAssocFields[i]; ++i )
3934         switch ( geomAssocFields[i] ) {
3935         case 'v':case 'e':case 'f':case 's': break;
3936         case 'V':case 'E':case 'F':case 'S': break;
3937         default: THROW_SALOME_CORBA_EXCEPTION
3938             ( "geomAssocFields can include only [vefs] characters", SALOME::BAD_PARAM);
3939         }
3940   }
3941
3942   SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
3943
3944   // write mesh
3945
3946   string aMeshName = "Mesh";
3947   SMESHUtils::Deleter< SMESH_MeshPartDS > tmpDSDeleter(0);
3948   if ( CORBA::is_nil( meshPart ) ||
3949        SMESH::DownCast< SMESH_Mesh_i* >( meshPart ))
3950   {
3951     aMeshName = prepareMeshNameAndGroups(file, overwrite);
3952     _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version,
3953                       0, autoDimension, /*addODOnVertices=*/have0dField,
3954                       ZTolerance);
3955     meshDS = _impl->GetMeshDS();
3956   }
3957   else
3958   {
3959     if ( _preMeshInfo )
3960       _preMeshInfo->FullLoadFromFile();
3961
3962     PrepareForWriting(file, overwrite);
3963
3964     SALOMEDS::SObject_wrap SO = _gen_i->ObjectToSObject( meshPart );
3965     if ( !SO->_is_nil() ) {
3966       CORBA::String_var name = SO->GetName();
3967       aMeshName = name;
3968     }
3969
3970     SMESH_MeshPartDS* partDS = new SMESH_MeshPartDS( meshPart );
3971     _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version,
3972                       partDS, autoDimension, /*addODOnVertices=*/have0dField, ZTolerance);
3973     meshDS = tmpDSDeleter._obj = partDS;
3974   }
3975
3976   // write fields
3977
3978   if ( _impl->HasShapeToMesh() )
3979   {
3980     DriverMED_W_Field fieldWriter;
3981     fieldWriter.SetFile( file );
3982     fieldWriter.SetMeshName( aMeshName );
3983     fieldWriter.AddODOnVertices( have0dField );
3984
3985     exportMEDFields( fieldWriter, meshDS, fields, geomAssocFields );
3986   }
3987
3988   // dump
3989   GEOM::ListOfGBO_var goList = new GEOM::ListOfGBO;
3990   goList->length( fields.length() );
3991   for ( size_t i = 0; i < fields.length(); ++i )
3992   {
3993     GEOM::GEOM_BaseObject_var gbo = GEOM::GEOM_BaseObject::_narrow( fields[i] );
3994     goList[i] = gbo;
3995   }
3996   TPythonDump() << _this() << ".ExportPartToMED( "
3997                 << meshPart << ", r'"
3998                 << file << "', "
3999                 << auto_groups << ", "
4000                 << version << ", "
4001                 << overwrite << ", "
4002                 << autoDimension << ", "
4003                 << goList << ", '"
4004                 << ( geomAssocFields ? geomAssocFields : "" ) << "',"
4005                 << TVar( ZTolerance )
4006                 << " )";
4007
4008   SMESH_CATCH( SMESH::throwCorbaException );
4009 }
4010
4011 //================================================================================
4012 /*!
4013  * Write GEOM fields to MED file
4014  */
4015 //================================================================================
4016
4017 void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
4018                                     SMESHDS_Mesh*             meshDS,
4019                                     const GEOM::ListOfFields& fields,
4020                                     const char*               geomAssocFields)
4021 {
4022 #define METH "SMESH_Mesh_i::exportMEDFields() "
4023
4024   if (( fields.length() < 1 ) &&
4025       ( !geomAssocFields || !geomAssocFields[0] ))
4026     return;
4027
4028   std::vector< std::vector< double > > dblVals;
4029   std::vector< std::vector< int > >    intVals;
4030   std::vector< int >                   subIdsByDim[ 4 ];
4031   const double noneDblValue = 0.;
4032   const double noneIntValue = 0;
4033
4034   for ( size_t iF = 0; iF < fields.length(); ++iF )
4035   {
4036     // set field data
4037
4038     int dim = fields[ iF ]->GetDimension();
4039     SMDSAbs_ElementType elemType;
4040     TopAbs_ShapeEnum    shapeType;
4041     switch ( dim ) {
4042     case 0: elemType = SMDSAbs_0DElement; shapeType = TopAbs_VERTEX; break;
4043     case 1: elemType = SMDSAbs_Edge;      shapeType = TopAbs_EDGE;   break;
4044     case 2: elemType = SMDSAbs_Face;      shapeType = TopAbs_FACE;   break;
4045     case 3: elemType = SMDSAbs_Volume;    shapeType = TopAbs_SOLID;  break;
4046     default:
4047       continue; // skip fields on whole shape
4048     }
4049     GEOM::field_data_type dataType = fields[ iF ]->GetDataType();
4050     if ( dataType == GEOM::FDT_String )
4051       continue;
4052     GEOM::ListOfLong_var stepIDs = fields[ iF ]->GetSteps();
4053     if ( stepIDs->length() < 1 )
4054       continue;
4055     GEOM::string_array_var comps = fields[ iF ]->GetComponents();
4056     if ( comps->length() < 1 )
4057       continue;
4058     CORBA::String_var       name = fields[ iF ]->GetName();
4059
4060     if ( !fieldWriter.Set( meshDS,
4061                            name.in(),
4062                            elemType,
4063                            comps->length(),
4064                            /*isIntData=*/false ))//( dataType == GEOM::FDT_Int )))
4065       continue;
4066
4067     for ( size_t iC = 0; iC < comps->length(); ++iC )
4068       fieldWriter.SetCompName( iC, comps[ iC ].in() );
4069
4070     dblVals.resize( comps->length() );
4071     intVals.resize( comps->length() );
4072
4073     // find sub-shape IDs
4074
4075     std::vector< int >& subIds = subIdsByDim[ dim ];
4076     if ( subIds.empty() )
4077       for ( int id = 1; id <= meshDS->MaxShapeIndex(); ++id )
4078         if ( meshDS->IndexToShape( id ).ShapeType() == shapeType )
4079           subIds.push_back( id );
4080
4081     // write steps
4082
4083     SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
4084     if ( !elemIt )
4085       continue;
4086
4087     for ( size_t iS = 0; iS < stepIDs->length(); ++iS )
4088     {
4089       GEOM::GEOM_FieldStep_var step = fields[ iF ]->GetStep( stepIDs[ iS ]);
4090       if ( step->_is_nil() )
4091         continue;
4092
4093       CORBA::Long stamp = step->GetStamp();
4094       CORBA::Long id    = step->GetID();
4095       fieldWriter.SetDtIt( int( stamp ), int( id ));
4096
4097       // fill dblVals or intVals
4098       for ( size_t iC = 0; iC < comps->length(); ++iC )
4099         if ( dataType == GEOM::FDT_Double )
4100         {
4101           dblVals[ iC ].clear();
4102           dblVals[ iC ].resize( meshDS->MaxShapeIndex()+1, 0 );
4103         }
4104         else
4105         {
4106           intVals[ iC ].clear();
4107           intVals[ iC ].resize( meshDS->MaxShapeIndex()+1, 0 );
4108         }
4109       switch ( dataType )
4110       {
4111       case GEOM::FDT_Double:
4112       {
4113         GEOM::GEOM_DoubleFieldStep_var dblStep = GEOM::GEOM_DoubleFieldStep::_narrow( step );
4114         if ( dblStep->_is_nil() ) continue;
4115         GEOM::ListOfDouble_var vv = dblStep->GetValues();
4116         if ( vv->length() != subIds.size() * comps->length() )
4117           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
4118         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
4119           for ( size_t iC = 0; iC < comps->length(); ++iC )
4120             dblVals[ iC ][ subIds[ iS ]] = vv[ iV++ ];
4121         break;
4122       }
4123       case GEOM::FDT_Int:
4124       {
4125         GEOM::GEOM_IntFieldStep_var intStep = GEOM::GEOM_IntFieldStep::_narrow( step );
4126         if ( intStep->_is_nil() ) continue;
4127         GEOM::ListOfLong_var vv = intStep->GetValues();
4128         if ( vv->length() != subIds.size() * comps->length() )
4129           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
4130         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
4131           for ( size_t iC = 0; iC < comps->length(); ++iC )
4132             intVals[ iC ][ subIds[ iS ]] = (int) vv[ iV++ ];
4133         break;
4134       }
4135       case GEOM::FDT_Bool:
4136       {
4137         GEOM::GEOM_BoolFieldStep_var boolStep = GEOM::GEOM_BoolFieldStep::_narrow( step );
4138         if ( boolStep->_is_nil() ) continue;
4139         GEOM::short_array_var vv = boolStep->GetValues();
4140         if ( vv->length() != subIds.size() * comps->length() )
4141           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
4142         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
4143           for ( size_t iC = 0; iC < comps->length(); ++iC )
4144             intVals[ iC ][ subIds[ iS ]] = (int) vv[ iV++ ];
4145         break;
4146       }
4147       default: continue;
4148       }
4149
4150       // pass values to fieldWriter
4151       elemIt = fieldWriter.GetOrderedElems();
4152       if ( dataType == GEOM::FDT_Double )
4153         while ( elemIt->more() )
4154         {
4155           const SMDS_MeshElement* e = elemIt->next();
4156           const int shapeID = e->getshapeId();
4157           if ( shapeID < 1 || shapeID >= (int) dblVals[0].size() )
4158             for ( size_t iC = 0; iC < comps->length(); ++iC )
4159               fieldWriter.AddValue( noneDblValue );
4160           else
4161             for ( size_t iC = 0; iC < comps->length(); ++iC )
4162               fieldWriter.AddValue( dblVals[ iC ][ shapeID ]);
4163         }
4164       else
4165         while ( elemIt->more() )
4166         {
4167           const SMDS_MeshElement* e = elemIt->next();
4168           const int shapeID = e->getshapeId();
4169           if ( shapeID < 1 || shapeID >= (int) intVals[0].size() )
4170             for ( size_t iC = 0; iC < comps->length(); ++iC )
4171               fieldWriter.AddValue( (double) noneIntValue );
4172           else
4173             for ( size_t iC = 0; iC < comps->length(); ++iC )
4174               fieldWriter.AddValue( (double) intVals[ iC ][ shapeID ]);
4175         }
4176
4177       // write a step
4178       fieldWriter.Perform();
4179       SMESH_ComputeErrorPtr res = fieldWriter.GetError();
4180       if ( res && res->IsKO() )
4181       {
4182         if ( res->myComment.empty() )
4183         { THROW_SALOME_CORBA_EXCEPTION( METH "Fatal error", SALOME::INTERNAL_ERROR ); }
4184         else
4185         { THROW_SALOME_CORBA_EXCEPTION( res->myComment.c_str(), SALOME::INTERNAL_ERROR ); }
4186       }
4187
4188     } // loop on steps
4189   } // loop on fields
4190
4191   if ( !geomAssocFields || !geomAssocFields[0] )
4192     return;
4193
4194   // write geomAssocFields
4195
4196   std::vector< int > shapeDim( TopAbs_SHAPE + 1 );
4197   shapeDim[ TopAbs_COMPOUND  ] = 3;
4198   shapeDim[ TopAbs_COMPSOLID ] = 3;
4199   shapeDim[ TopAbs_SOLID     ] = 3;
4200   shapeDim[ TopAbs_SHELL     ] = 2;
4201   shapeDim[ TopAbs_FACE      ] = 2;
4202   shapeDim[ TopAbs_WIRE      ] = 1;
4203   shapeDim[ TopAbs_EDGE      ] = 1;
4204   shapeDim[ TopAbs_VERTEX    ] = 0;
4205   shapeDim[ TopAbs_SHAPE     ] = 3;
4206
4207   for ( int iF = 0; geomAssocFields[ iF ]; ++iF )
4208   {
4209     std::vector< std::string > compNames;
4210     switch ( geomAssocFields[ iF ]) {
4211     case 'v': case 'V':
4212       fieldWriter.Set( meshDS, "_vertices_", SMDSAbs_Node, /*nbComps=*/2, /*isInt=*/false );
4213       compNames.push_back( "dim" );
4214       break;
4215     case 'e': case 'E':
4216       fieldWriter.Set( meshDS, "_edges_", SMDSAbs_Edge, /*nbComps=*/1, /*isInt=*/false );
4217       break;
4218     case 'f': case 'F':
4219       fieldWriter.Set( meshDS, "_faces_", SMDSAbs_Face, /*nbComps=*/1, /*isInt=*/false );
4220       break;
4221     case 's': case 'S':
4222       fieldWriter.Set( meshDS, "_solids_", SMDSAbs_Volume, /*nbComps=*/1, /*isInt=*/false );
4223       break;
4224     default: continue;
4225     }
4226     compNames.push_back( "id" );
4227     for ( size_t iC = 0; iC < compNames.size(); ++iC )
4228       fieldWriter.SetCompName( iC, compNames[ iC ].c_str() );
4229
4230     fieldWriter.SetDtIt( -1, -1 );
4231
4232     SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
4233     if ( !elemIt )
4234       continue;
4235
4236     if ( compNames.size() == 2 ) // _vertices_
4237       while ( elemIt->more() )
4238       {
4239         const SMDS_MeshElement* e = elemIt->next();
4240         const int shapeID = e->getshapeId();
4241         if ( shapeID < 1 )
4242         {
4243           fieldWriter.AddValue( (double) -1 );
4244           fieldWriter.AddValue( (double) -1 );
4245         }
4246         else
4247         {
4248           const TopoDS_Shape& S = meshDS->IndexToShape( shapeID );
4249           fieldWriter.AddValue( (double) ( S.IsNull() ? -1 : shapeDim[ S.ShapeType() ]));
4250           fieldWriter.AddValue( (double) shapeID );
4251         }
4252       }
4253     else
4254       while ( elemIt->more() )
4255       {
4256         const SMDS_MeshElement* e = elemIt->next();
4257         const int shapeID = e->getshapeId();
4258         if ( shapeID < 1 )
4259           fieldWriter.AddValue( (double) -1 );
4260         else
4261           fieldWriter.AddValue( (double) shapeID );
4262       }
4263
4264     // write a step
4265     fieldWriter.Perform();
4266     SMESH_ComputeErrorPtr res = fieldWriter.GetError();
4267     if ( res && res->IsKO() )
4268     {
4269       if ( res->myComment.empty() )
4270       { THROW_SALOME_CORBA_EXCEPTION( METH "Fatal error", SALOME::INTERNAL_ERROR ); }
4271       else
4272       { THROW_SALOME_CORBA_EXCEPTION( res->myComment.c_str(), SALOME::INTERNAL_ERROR ); }
4273     }
4274
4275   } // loop on geomAssocFields
4276
4277 #undef METH
4278 }
4279
4280 //================================================================================
4281 /*!
4282  * \brief Export a part of mesh to a DAT file
4283  */
4284 //================================================================================
4285
4286 void SMESH_Mesh_i::ExportPartToDAT(::SMESH::SMESH_IDSource_ptr meshPart,
4287                                    const char*                 file)
4288   throw (SALOME::SALOME_Exception)
4289 {
4290   Unexpect aCatch(SALOME_SalomeException);
4291   if ( _preMeshInfo )
4292     _preMeshInfo->FullLoadFromFile();
4293
4294   PrepareForWriting(file);
4295
4296   SMESH_MeshPartDS partDS( meshPart );
4297   _impl->ExportDAT(file,&partDS);
4298
4299   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
4300                 << ".ExportPartToDAT( " << meshPart << ", r'" << file << "' )";
4301 }
4302 //================================================================================
4303 /*!
4304  * \brief Export a part of mesh to an UNV file
4305  */
4306 //================================================================================
4307
4308 void SMESH_Mesh_i::ExportPartToUNV(::SMESH::SMESH_IDSource_ptr meshPart,
4309                                    const char*                 file)
4310   throw (SALOME::SALOME_Exception)
4311 {
4312   Unexpect aCatch(SALOME_SalomeException);
4313   if ( _preMeshInfo )
4314     _preMeshInfo->FullLoadFromFile();
4315
4316   PrepareForWriting(file);
4317
4318   SMESH_MeshPartDS partDS( meshPart );
4319   _impl->ExportUNV(file, &partDS);
4320
4321   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
4322                 << ".ExportPartToUNV( " << meshPart<< ", r'" << file << "' )";
4323 }
4324 //================================================================================
4325 /*!
4326  * \brief Export a part of mesh to an STL file
4327  */
4328 //================================================================================
4329
4330 void SMESH_Mesh_i::ExportPartToSTL(::SMESH::SMESH_IDSource_ptr meshPart,
4331                                    const char*                 file,
4332                                    ::CORBA::Boolean            isascii)
4333   throw (SALOME::SALOME_Exception)
4334 {
4335   Unexpect aCatch(SALOME_SalomeException);
4336   if ( _preMeshInfo )
4337     _preMeshInfo->FullLoadFromFile();
4338
4339   PrepareForWriting(file);
4340
4341   CORBA::String_var name;
4342   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( meshPart );
4343   if ( !so->_is_nil() )
4344     name = so->GetName();
4345
4346   SMESH_MeshPartDS partDS( meshPart );
4347   _impl->ExportSTL( file, isascii, name.in(), &partDS );
4348
4349   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportPartToSTL( "
4350                 << meshPart<< ", r'" << file << "', " << isascii << ")";
4351 }
4352
4353 //================================================================================
4354 /*!
4355  * \brief Export a part of mesh to an STL file
4356  */
4357 //================================================================================
4358
4359 void SMESH_Mesh_i::ExportCGNS(::SMESH::SMESH_IDSource_ptr meshPart,
4360                               const char*                 file,
4361                               CORBA::Boolean              overwrite,
4362                               CORBA::Boolean              groupElemsByType)
4363   throw (SALOME::SALOME_Exception)
4364 {
4365 #ifdef WITH_CGNS
4366   Unexpect aCatch(SALOME_SalomeException);
4367   if ( _preMeshInfo )
4368     _preMeshInfo->FullLoadFromFile();
4369
4370   PrepareForWriting(file,overwrite);
4371
4372   std::string meshName("");
4373   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( meshPart );
4374   if ( !so->_is_nil() )
4375   {
4376     CORBA::String_var name = so->GetName();
4377     meshName = name.in();
4378   }
4379   SMESH_TRY;
4380
4381   SMESH_MeshPartDS partDS( meshPart );
4382   _impl->ExportCGNS(file, &partDS, meshName.c_str(), groupElemsByType );
4383
4384   SMESH_CATCH( SMESH::throwCorbaException );
4385
4386   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportCGNS( "
4387                 << meshPart<< ", r'" << file << "', " << overwrite << ")";
4388 #else
4389   THROW_SALOME_CORBA_EXCEPTION("CGNS library is unavailable", SALOME::INTERNAL_ERROR);
4390 #endif
4391 }
4392
4393 //================================================================================
4394 /*!
4395  * \brief Export a part of mesh to a GMF file
4396  */
4397 //================================================================================
4398
4399 void SMESH_Mesh_i::ExportGMF(::SMESH::SMESH_IDSource_ptr meshPart,
4400                              const char*                 file,
4401                              bool                        withRequiredGroups)
4402   throw (SALOME::SALOME_Exception)
4403 {
4404   Unexpect aCatch(SALOME_SalomeException);
4405   if ( _preMeshInfo )
4406     _preMeshInfo->FullLoadFromFile();
4407
4408   PrepareForWriting(file,/*overwrite=*/true);
4409
4410   SMESH_MeshPartDS partDS( meshPart );
4411   _impl->ExportGMF(file, &partDS, withRequiredGroups);
4412
4413   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportGMF( "
4414                 << meshPart<< ", r'"
4415                 << file << "', "
4416                 << withRequiredGroups << ")";
4417 }
4418
4419 //=============================================================================
4420 /*!
4421  * Return computation progress [0.,1]
4422  */
4423 //=============================================================================
4424
4425 CORBA::Double SMESH_Mesh_i::GetComputeProgress()
4426 {
4427   SMESH_TRY;
4428
4429   return _impl->GetComputeProgress();
4430
4431   SMESH_CATCH( SMESH::doNothing );
4432   return 0.;
4433 }
4434
4435 //================================================================================
4436 /*!
4437  * \brief Return nb of nodes
4438  */
4439 //================================================================================
4440
4441 CORBA::Long SMESH_Mesh_i::NbNodes()throw(SALOME::SALOME_Exception)
4442 {
4443   Unexpect aCatch(SALOME_SalomeException);
4444   if ( _preMeshInfo )
4445     return _preMeshInfo->NbNodes();
4446
4447   return _impl->NbNodes();
4448 }
4449
4450 //================================================================================
4451 /*!
4452  * \brief Return nb of elements
4453  */
4454 //================================================================================
4455
4456 CORBA::Long SMESH_Mesh_i::NbElements()throw (SALOME::SALOME_Exception)
4457 {
4458   Unexpect aCatch(SALOME_SalomeException);
4459   if ( _preMeshInfo )
4460     return _preMeshInfo->NbElements();
4461
4462   return Nb0DElements() + NbEdges() + NbFaces() + NbVolumes() + NbBalls();
4463 }
4464
4465 //================================================================================
4466 /*!
4467  * \brief Return nb of 0D elements
4468  */
4469 //================================================================================
4470
4471 CORBA::Long SMESH_Mesh_i::Nb0DElements()throw (SALOME::SALOME_Exception)
4472 {
4473   Unexpect aCatch(SALOME_SalomeException);
4474   if ( _preMeshInfo )
4475     return _preMeshInfo->Nb0DElements();
4476
4477   return _impl->Nb0DElements();
4478 }
4479
4480 //================================================================================
4481 /*!
4482  * \brief Return nb of BALL elements
4483  */
4484 //================================================================================
4485
4486 CORBA::Long SMESH_Mesh_i::NbBalls() throw (SALOME::SALOME_Exception)
4487 {
4488   Unexpect aCatch(SALOME_SalomeException);
4489   if ( _preMeshInfo )
4490     return _preMeshInfo->NbBalls();
4491
4492   return _impl->NbBalls();
4493 }
4494
4495 //================================================================================
4496 /*!
4497  * \brief Return nb of 1D elements
4498  */
4499 //================================================================================
4500
4501 CORBA::Long SMESH_Mesh_i::NbEdges()throw(SALOME::SALOME_Exception)
4502 {
4503   Unexpect aCatch(SALOME_SalomeException);
4504   if ( _preMeshInfo )
4505     return _preMeshInfo->NbEdges();
4506
4507   return _impl->NbEdges();
4508 }
4509
4510 //================================================================================
4511 /*!
4512  * \brief Return nb of edges
4513  */
4514 //================================================================================
4515
4516 CORBA::Long SMESH_Mesh_i::NbEdgesOfOrder(SMESH::ElementOrder order)
4517   throw(SALOME::SALOME_Exception)
4518 {
4519   Unexpect aCatch(SALOME_SalomeException);
4520   if ( _preMeshInfo )
4521     return _preMeshInfo->NbEdges( (SMDSAbs_ElementOrder) order );
4522
4523   return _impl->NbEdges( (SMDSAbs_ElementOrder) order);
4524 }
4525
4526 //================================================================================
4527 /*!
4528  * \brief Return nb of faces
4529  */
4530 //================================================================================
4531
4532 CORBA::Long SMESH_Mesh_i::NbFaces()throw(SALOME::SALOME_Exception)
4533 {
4534   Unexpect aCatch(SALOME_SalomeException);
4535   if ( _preMeshInfo )
4536     return _preMeshInfo->NbFaces();
4537
4538   return _impl->NbFaces();
4539 }
4540
4541 //================================================================================
4542 /*!
4543  * \brief Return nb of tringles
4544  */
4545 //================================================================================
4546
4547 CORBA::Long SMESH_Mesh_i::NbTriangles()throw(SALOME::SALOME_Exception)
4548 {
4549   Unexpect aCatch(SALOME_SalomeException);
4550   if ( _preMeshInfo )
4551     return _preMeshInfo->NbTriangles();
4552
4553   return _impl->NbTriangles();
4554 }
4555
4556 //================================================================================
4557 /*!
4558  * \brief Return nb of bi-quadratic triangles
4559  */
4560 //================================================================================
4561
4562 CORBA::Long SMESH_Mesh_i::NbBiQuadTriangles()throw(SALOME::SALOME_Exception)
4563 {
4564   Unexpect aCatch(SALOME_SalomeException);
4565   if ( _preMeshInfo )
4566     return _preMeshInfo->NbBiQuadTriangles();
4567
4568   return _impl->NbBiQuadTriangles();
4569 }
4570
4571 CORBA::Long SMESH_Mesh_i::NbQuadrangles()throw(SALOME::SALOME_Exception)
4572 {
4573   Unexpect aCatch(SALOME_SalomeException);
4574   if ( _preMeshInfo )
4575     return _preMeshInfo->NbQuadrangles();
4576
4577   return _impl->NbQuadrangles();
4578 }
4579
4580 CORBA::Long SMESH_Mesh_i::NbBiQuadQuadrangles()throw(SALOME::SALOME_Exception)
4581 {
4582   Unexpect aCatch(SALOME_SalomeException);
4583   if ( _preMeshInfo )
4584     return _preMeshInfo->NbBiQuadQuadrangles();
4585
4586   return _impl->NbBiQuadQuadrangles();
4587 }
4588
4589 CORBA::Long SMESH_Mesh_i::NbPolygons() throw(SALOME::SALOME_Exception)
4590 {
4591   Unexpect aCatch(SALOME_SalomeException);
4592   if ( _preMeshInfo )
4593     return _preMeshInfo->NbPolygons();
4594
4595   return _impl->NbPolygons();
4596 }
4597
4598 CORBA::Long SMESH_Mesh_i::NbPolygonsOfOrder(SMESH::ElementOrder order) throw(SALOME::SALOME_Exception)
4599 {
4600   Unexpect aCatch(SALOME_SalomeException);
4601   if ( _preMeshInfo )
4602     return _preMeshInfo->NbPolygons((SMDSAbs_ElementOrder) order);
4603
4604   return _impl->NbPolygons((SMDSAbs_ElementOrder)order);
4605 }
4606
4607 CORBA::Long SMESH_Mesh_i::NbFacesOfOrder(SMESH::ElementOrder order)
4608   throw(SALOME::SALOME_Exception)
4609 {
4610   Unexpect aCatch(SALOME_SalomeException);
4611   if ( _preMeshInfo )
4612     return _preMeshInfo->NbFaces( (SMDSAbs_ElementOrder) order );
4613
4614   return _impl->NbFaces( (SMDSAbs_ElementOrder) order);
4615 }
4616
4617 CORBA::Long SMESH_Mesh_i::NbTrianglesOfOrder(SMESH::ElementOrder order)
4618   throw(SALOME::SALOME_Exception)
4619 {
4620   Unexpect aCatch(SALOME_SalomeException);
4621   if ( _preMeshInfo )
4622     return _preMeshInfo->NbTriangles( (SMDSAbs_ElementOrder) order );
4623
4624   return _impl->NbTriangles( (SMDSAbs_ElementOrder) order);
4625 }
4626
4627 CORBA::Long SMESH_Mesh_i::NbQuadranglesOfOrder(SMESH::ElementOrder order)
4628   throw(SALOME::SALOME_Exception)
4629 {
4630   Unexpect aCatch(SALOME_SalomeException);
4631   if ( _preMeshInfo )
4632     return _preMeshInfo->NbQuadrangles( (SMDSAbs_ElementOrder) order );
4633
4634   return _impl->NbQuadrangles( (SMDSAbs_ElementOrder) order);
4635 }
4636
4637 //=============================================================================
4638
4639 CORBA::Long SMESH_Mesh_i::NbVolumes()throw(SALOME::SALOME_Exception)
4640 {
4641   Unexpect aCatch(SALOME_SalomeException);
4642   if ( _preMeshInfo )
4643     return _preMeshInfo->NbVolumes();
4644
4645   return _impl->NbVolumes();
4646 }
4647
4648 CORBA::Long SMESH_Mesh_i::NbTetras()throw(SALOME::SALOME_Exception)
4649 {
4650   Unexpect aCatch(SALOME_SalomeException);
4651   if ( _preMeshInfo )
4652     return _preMeshInfo->NbTetras();
4653
4654   return _impl->NbTetras();
4655 }
4656
4657 CORBA::Long SMESH_Mesh_i::NbHexas()throw(SALOME::SALOME_Exception)
4658 {
4659   Unexpect aCatch(SALOME_SalomeException);
4660   if ( _preMeshInfo )
4661     return _preMeshInfo->NbHexas();
4662
4663   return _impl->NbHexas();
4664 }
4665
4666 CORBA::Long SMESH_Mesh_i::NbTriQuadraticHexas()throw(SALOME::SALOME_Exception)
4667 {
4668   Unexpect aCatch(SALOME_SalomeException);
4669   if ( _preMeshInfo )
4670     return _preMeshInfo->NbTriQuadHexas();
4671
4672   return _impl->NbTriQuadraticHexas();
4673 }
4674
4675 CORBA::Long SMESH_Mesh_i::NbPyramids()throw(SALOME::SALOME_Exception)
4676 {
4677   Unexpect aCatch(SALOME_SalomeException);
4678   if ( _preMeshInfo )
4679     return _preMeshInfo->NbPyramids();
4680
4681   return _impl->NbPyramids();
4682 }
4683
4684 CORBA::Long SMESH_Mesh_i::NbPrisms()throw(SALOME::SALOME_Exception)
4685 {
4686   Unexpect aCatch(SALOME_SalomeException);
4687   if ( _preMeshInfo )
4688     return _preMeshInfo->NbPrisms();
4689
4690   return _impl->NbPrisms();
4691 }
4692
4693 CORBA::Long SMESH_Mesh_i::NbHexagonalPrisms()throw(SALOME::SALOME_Exception)
4694 {
4695   Unexpect aCatch(SALOME_SalomeException);
4696   if ( _preMeshInfo )
4697     return _preMeshInfo->NbHexPrisms();
4698
4699   return _impl->NbHexagonalPrisms();
4700 }
4701
4702 CORBA::Long SMESH_Mesh_i::NbPolyhedrons()throw(SALOME::SALOME_Exception)
4703 {
4704   Unexpect aCatch(SALOME_SalomeException);
4705   if ( _preMeshInfo )
4706     return _preMeshInfo->NbPolyhedrons();
4707
4708   return _impl->NbPolyhedrons();
4709 }
4710
4711 CORBA::Long SMESH_Mesh_i::NbVolumesOfOrder(SMESH::ElementOrder order)
4712   throw(SALOME::SALOME_Exception)
4713 {
4714   Unexpect aCatch(SALOME_SalomeException);
4715   if ( _preMeshInfo )
4716     return _preMeshInfo->NbVolumes( (SMDSAbs_ElementOrder) order );
4717
4718   return _impl->NbVolumes( (SMDSAbs_ElementOrder) order);
4719 }
4720
4721 CORBA::Long SMESH_Mesh_i::NbTetrasOfOrder(SMESH::ElementOrder order)
4722   throw(SALOME::SALOME_Exception)
4723 {
4724   Unexpect aCatch(SALOME_SalomeException);
4725   if ( _preMeshInfo )
4726     return _preMeshInfo->NbTetras( (SMDSAbs_ElementOrder) order);
4727
4728   return _impl->NbTetras( (SMDSAbs_ElementOrder) order);
4729 }
4730
4731 CORBA::Long SMESH_Mesh_i::NbHexasOfOrder(SMESH::ElementOrder order)
4732   throw(SALOME::SALOME_Exception)
4733 {
4734   Unexpect aCatch(SALOME_SalomeException);
4735   if ( _preMeshInfo )
4736     return _preMeshInfo->NbHexas( (SMDSAbs_ElementOrder) order);
4737
4738   return _impl->NbHexas( (SMDSAbs_ElementOrder) order);
4739 }
4740
4741 CORBA::Long SMESH_Mesh_i::NbPyramidsOfOrder(SMESH::ElementOrder order)
4742   throw(SALOME::SALOME_Exception)
4743 {
4744   Unexpect aCatch(SALOME_SalomeException);
4745   if ( _preMeshInfo )
4746     return _preMeshInfo->NbPyramids( (SMDSAbs_ElementOrder) order);
4747
4748   return _impl->NbPyramids( (SMDSAbs_ElementOrder) order);
4749 }
4750
4751 CORBA::Long SMESH_Mesh_i::NbPrismsOfOrder(SMESH::ElementOrder order)
4752   throw(SALOME::SALOME_Exception)
4753 {
4754   Unexpect aCatch(SALOME_SalomeException);
4755   if ( _preMeshInfo )
4756     return _preMeshInfo->NbPrisms( (SMDSAbs_ElementOrder) order);
4757
4758   return _impl->NbPrisms( (SMDSAbs_ElementOrder) order);
4759 }
4760
4761 //=============================================================================
4762 /*!
4763  * Return nb of published sub-meshes
4764  */
4765 //=============================================================================
4766
4767 CORBA::Long SMESH_Mesh_i::NbSubMesh()throw(SALOME::SALOME_Exception)
4768 {
4769   Unexpect aCatch(SALOME_SalomeException);
4770   return _mapSubMesh_i.size();
4771 }
4772
4773 //=============================================================================
4774 /*!
4775  * Dumps mesh into a string
4776  */
4777 //=============================================================================
4778
4779 char* SMESH_Mesh_i::Dump()
4780 {
4781   ostringstream os;
4782   _impl->Dump( os );
4783   return CORBA::string_dup( os.str().c_str() );
4784 }
4785
4786 //=============================================================================
4787 /*!
4788  * Method of SMESH_IDSource interface
4789  */
4790 //=============================================================================
4791
4792 SMESH::long_array* SMESH_Mesh_i::GetIDs()
4793 {
4794   return GetElementsId();
4795 }
4796
4797 //=============================================================================
4798 /*!
4799  * Return ids of all elements
4800  */
4801 //=============================================================================
4802
4803 SMESH::long_array* SMESH_Mesh_i::GetElementsId()
4804   throw (SALOME::SALOME_Exception)
4805 {
4806   Unexpect aCatch(SALOME_SalomeException);
4807   if ( _preMeshInfo )
4808     _preMeshInfo->FullLoadFromFile();
4809
4810   SMESH::long_array_var aResult = new SMESH::long_array();
4811   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
4812
4813   if ( aSMESHDS_Mesh == NULL )
4814     return aResult._retn();
4815
4816   long nbElements = NbElements();
4817   aResult->length( nbElements );
4818   SMDS_ElemIteratorPtr anIt = aSMESHDS_Mesh->elementsIterator();
4819   for ( int i = 0, n = nbElements; i < n && anIt->more(); i++ )
4820     aResult[i] = anIt->next()->GetID();
4821
4822   return aResult._retn();
4823 }
4824
4825
4826 //=============================================================================
4827 /*!
4828  * Return ids of all elements of given type
4829  */
4830 //=============================================================================
4831
4832 SMESH::long_array* SMESH_Mesh_i::GetElementsByType( SMESH::ElementType theElemType )
4833     throw (SALOME::SALOME_Exception)
4834 {
4835   Unexpect aCatch(SALOME_SalomeException);
4836   if ( _preMeshInfo )
4837     _preMeshInfo->FullLoadFromFile();
4838
4839   SMESH::long_array_var aResult = new SMESH::long_array();
4840   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
4841
4842   if ( aSMESHDS_Mesh == NULL )
4843     return aResult._retn();
4844
4845   long nbElements = NbElements();
4846
4847   // No sense in returning ids of elements along with ids of nodes:
4848   // when theElemType == SMESH::ALL, return node ids only if
4849   // there are no elements
4850   if ( theElemType == SMESH::NODE || (theElemType == SMESH::ALL && nbElements == 0) )
4851     return GetNodesId();
4852
4853   aResult->length( nbElements );
4854
4855   int i = 0;
4856
4857   SMDS_ElemIteratorPtr anIt = aSMESHDS_Mesh->elementsIterator( (SMDSAbs_ElementType)theElemType );
4858   while ( i < nbElements && anIt->more() )
4859     aResult[i++] = anIt->next()->GetID();
4860
4861   aResult->length( i );
4862
4863   return aResult._retn();
4864 }
4865
4866 //=============================================================================
4867 /*!
4868  * Return ids of all nodes
4869  */
4870 //=============================================================================
4871
4872 SMESH::long_array* SMESH_Mesh_i::GetNodesId()
4873   throw (SALOME::SALOME_Exception)
4874 {
4875   Unexpect aCatch(SALOME_SalomeException);
4876   if ( _preMeshInfo )
4877     _preMeshInfo->FullLoadFromFile();
4878
4879   SMESH::long_array_var aResult = new SMESH::long_array();
4880   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4881
4882   if ( aMeshDS == NULL )
4883     return aResult._retn();
4884
4885   long nbNodes = NbNodes();
4886   aResult->length( nbNodes );
4887   SMDS_NodeIteratorPtr anIt = aMeshDS->nodesIterator();
4888   for ( int i = 0, n = nbNodes; i < n && anIt->more(); i++ )
4889     aResult[i] = anIt->next()->GetID();
4890
4891   return aResult._retn();
4892 }
4893
4894 //=============================================================================
4895 /*!
4896  * Return type of the given element
4897  */
4898 //=============================================================================
4899
4900 SMESH::ElementType SMESH_Mesh_i::GetElementType( const CORBA::Long id, const bool iselem )
4901   throw (SALOME::SALOME_Exception)
4902 {
4903   SMESH::ElementType type = SMESH::ALL;
4904   SMESH_TRY;
4905
4906   if ( _preMeshInfo )
4907     _preMeshInfo->FullLoadFromFile();
4908
4909   type = ( SMESH::ElementType ) _impl->GetElementType( id, iselem );
4910
4911   SMESH_CATCH( SMESH::throwCorbaException );
4912
4913   return type;
4914 }
4915
4916 //=============================================================================
4917 /*!
4918  * Return geometric type of the given element
4919  */
4920 //=============================================================================
4921
4922 SMESH::EntityType SMESH_Mesh_i::GetElementGeomType( const CORBA::Long id )
4923   throw (SALOME::SALOME_Exception)
4924 {
4925   if ( _preMeshInfo )
4926     _preMeshInfo->FullLoadFromFile();
4927
4928   const SMDS_MeshElement* e = _impl->GetMeshDS()->FindElement(id);
4929   if ( !e )
4930     THROW_SALOME_CORBA_EXCEPTION( "invalid element id", SALOME::BAD_PARAM );
4931
4932   return ( SMESH::EntityType ) e->GetEntityType();
4933 }
4934
4935 //=============================================================================
4936 /*!
4937  * Return type of the given element
4938  */
4939 //=============================================================================
4940
4941 SMESH::GeometryType SMESH_Mesh_i::GetElementShape( const CORBA::Long id )
4942   throw (SALOME::SALOME_Exception)
4943 {
4944   if ( _preMeshInfo )
4945     _preMeshInfo->FullLoadFromFile();
4946
4947   const SMDS_MeshElement* e = _impl->GetMeshDS()->FindElement(id);
4948   if ( !e )
4949     THROW_SALOME_CORBA_EXCEPTION( "invalid element id", SALOME::BAD_PARAM );
4950
4951   return ( SMESH::GeometryType ) e->GetGeomType();
4952 }
4953
4954 //=============================================================================
4955 /*!
4956  * Return ID of elements for given submesh
4957  */
4958 //=============================================================================
4959
4960 SMESH::long_array* SMESH_Mesh_i::GetSubMeshElementsId(const CORBA::Long ShapeID)
4961      throw (SALOME::SALOME_Exception)
4962 {
4963   SMESH::long_array_var aResult = new SMESH::long_array();
4964
4965   SMESH_TRY;
4966   if ( _preMeshInfo )
4967     _preMeshInfo->FullLoadFromFile();
4968
4969   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
4970   if(!SM) return aResult._retn();
4971
4972   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
4973   if(!SDSM) return aResult._retn();
4974
4975   aResult->length(SDSM->NbElements());
4976
4977   SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
4978   int i = 0;
4979   while ( eIt->more() ) {
4980     aResult[i++] = eIt->next()->GetID();
4981   }
4982
4983   SMESH_CATCH( SMESH::throwCorbaException );
4984
4985   return aResult._retn();
4986 }
4987
4988 //=============================================================================
4989 /*!
4990  * Return ID of nodes for given sub-mesh
4991  * If param all==true - return all nodes, else -
4992  * Return only nodes on shapes.
4993  */
4994 //=============================================================================
4995
4996 SMESH::long_array* SMESH_Mesh_i::GetSubMeshNodesId(const CORBA::Long ShapeID,
4997                                                    CORBA::Boolean    all)
4998   throw (SALOME::SALOME_Exception)
4999 {
5000   SMESH::long_array_var aResult = new SMESH::long_array();
5001
5002   SMESH_TRY;
5003   if ( _preMeshInfo )
5004     _preMeshInfo->FullLoadFromFile();
5005
5006   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
5007   if(!SM) return aResult._retn();
5008
5009   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
5010   if(!SDSM) return aResult._retn();
5011
5012   set<int> theElems;
5013   if( !all || (SDSM->NbElements()==0) ) { // internal nodes or vertex submesh
5014     SMDS_NodeIteratorPtr nIt = SDSM->GetNodes();
5015     while ( nIt->more() ) {
5016       const SMDS_MeshNode* elem = nIt->next();
5017       theElems.insert( elem->GetID() );
5018     }
5019   }
5020   else { // all nodes of submesh elements
5021     SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
5022     while ( eIt->more() ) {
5023       const SMDS_MeshElement* anElem = eIt->next();
5024       SMDS_ElemIteratorPtr nIt = anElem->nodesIterator();
5025       while ( nIt->more() ) {
5026         const SMDS_MeshElement* elem = nIt->next();
5027         theElems.insert( elem->GetID() );
5028       }
5029     }
5030   }
5031
5032   aResult->length(theElems.size());
5033   set<int>::iterator itElem;
5034   int i = 0;
5035   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5036     aResult[i++] = *itElem;
5037
5038   SMESH_CATCH( SMESH::throwCorbaException );
5039
5040   return aResult._retn();
5041 }
5042
5043 //=============================================================================
5044 /*!
5045  * Return type of elements for given sub-mesh
5046  */
5047 //=============================================================================
5048
5049 SMESH::ElementType SMESH_Mesh_i::GetSubMeshElementType(const CORBA::Long ShapeID)
5050   throw (SALOME::SALOME_Exception)
5051 {
5052   SMESH::ElementType type = SMESH::ALL;
5053
5054   SMESH_TRY;
5055   if ( _preMeshInfo )
5056     _preMeshInfo->FullLoadFromFile();
5057
5058   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
5059   if(!SM) return SMESH::ALL;
5060
5061   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
5062   if(!SDSM) return SMESH::ALL;
5063
5064   if(SDSM->NbElements()==0)
5065     return (SM->GetSubShape().ShapeType() == TopAbs_VERTEX) ? SMESH::NODE : SMESH::ALL;
5066
5067   SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
5068   const SMDS_MeshElement* anElem = eIt->next();
5069
5070   type = ( SMESH::ElementType ) anElem->GetType();
5071
5072   SMESH_CATCH( SMESH::throwCorbaException );
5073
5074   return type;
5075 }
5076
5077
5078 //=============================================================================
5079 /*!
5080  * Return pointer to _impl as an integer value. Is called from constructor of SMESH_Client
5081  */
5082 //=============================================================================
5083
5084 CORBA::LongLong SMESH_Mesh_i::GetMeshPtr()
5085 {
5086   if ( _preMeshInfo )
5087     _preMeshInfo->FullLoadFromFile();
5088
5089   CORBA::LongLong pointeur = CORBA::LongLong(_impl);
5090   if ( MYDEBUG ) MESSAGE("CORBA::LongLong SMESH_Mesh_i::GetMeshPtr() "<<pointeur);
5091   return pointeur;
5092 }
5093
5094
5095 //=============================================================================
5096 /*!
5097  * Get XYZ coordinates of node as list of double
5098  * If there is not node for given ID - return empty list
5099  */
5100 //=============================================================================
5101
5102 SMESH::double_array* SMESH_Mesh_i::GetNodeXYZ(const CORBA::Long id)
5103 {
5104   if ( _preMeshInfo )
5105     _preMeshInfo->FullLoadFromFile();
5106
5107   SMESH::double_array_var aResult = new SMESH::double_array();
5108   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5109   if ( aMeshDS == NULL )
5110     return aResult._retn();
5111
5112   // find node
5113   const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
5114   if(!aNode)
5115     return aResult._retn();
5116
5117   // add coordinates
5118   aResult->length(3);
5119   aResult[0] = aNode->X();
5120   aResult[1] = aNode->Y();
5121   aResult[2] = aNode->Z();
5122   return aResult._retn();
5123 }
5124
5125
5126 //=============================================================================
5127 /*!
5128  * For given node return list of IDs of inverse elements
5129  * If there is not node for given ID - return empty list
5130  */
5131 //=============================================================================
5132
5133 SMESH::long_array* SMESH_Mesh_i::GetNodeInverseElements(const CORBA::Long  id,
5134                                                         SMESH::ElementType elemType)
5135 {
5136   if ( _preMeshInfo )
5137     _preMeshInfo->FullLoadFromFile();
5138
5139   SMESH::long_array_var aResult = new SMESH::long_array();
5140   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5141   if ( aMeshDS == NULL )
5142     return aResult._retn();
5143
5144   // find node
5145   const SMDS_MeshNode* aNode = aMeshDS->FindNode( id );
5146   if ( !aNode )
5147     return aResult._retn();
5148
5149   // find inverse elements
5150   SMDSAbs_ElementType type = SMDSAbs_ElementType( elemType );
5151   SMDS_ElemIteratorPtr eIt = aNode->GetInverseElementIterator( type );
5152   aResult->length( aNode->NbInverseElements( type ));
5153   for( int i = 0; eIt->more(); ++i )
5154   {
5155     const SMDS_MeshElement* elem = eIt->next();
5156     aResult[ i ] = elem->GetID();
5157   }
5158   return aResult._retn();
5159 }
5160
5161 //=============================================================================
5162 /*!
5163  * \brief Return position of a node on shape
5164  */
5165 //=============================================================================
5166
5167 SMESH::NodePosition* SMESH_Mesh_i::GetNodePosition(CORBA::Long NodeID)
5168 {
5169   if ( _preMeshInfo )
5170     _preMeshInfo->FullLoadFromFile();
5171
5172   SMESH::NodePosition* aNodePosition = new SMESH::NodePosition();
5173   aNodePosition->shapeID = 0;
5174   aNodePosition->shapeType = GEOM::SHAPE;
5175
5176   SMESHDS_Mesh* mesh = _impl->GetMeshDS();
5177   if ( !mesh ) return aNodePosition;
5178
5179   if ( const SMDS_MeshNode* aNode = mesh->FindNode(NodeID) )
5180   {
5181     if ( SMDS_PositionPtr pos = aNode->GetPosition() )
5182     {
5183       aNodePosition->shapeID = aNode->getshapeId();
5184       switch ( pos->GetTypeOfPosition() ) {
5185       case SMDS_TOP_EDGE:
5186         aNodePosition->shapeType = GEOM::EDGE;
5187         aNodePosition->params.length(1);
5188         aNodePosition->params[0] = SMDS_EdgePositionPtr( pos )->GetUParameter();
5189         break;
5190       case SMDS_TOP_FACE: {
5191         SMDS_FacePositionPtr fPos = pos;
5192         aNodePosition->shapeType = GEOM::FACE;
5193         aNodePosition->params.length(2);
5194         aNodePosition->params[0] = fPos->GetUParameter();
5195         aNodePosition->params[1] = fPos->GetVParameter();
5196         break;
5197       }
5198       case SMDS_TOP_VERTEX:
5199         aNodePosition->shapeType = GEOM::VERTEX;
5200         break;
5201       case SMDS_TOP_3DSPACE:
5202         if ( TopExp_Explorer(_impl->GetShapeToMesh(), TopAbs_SOLID).More() )
5203           aNodePosition->shapeType = GEOM::SOLID;
5204         else if ( TopExp_Explorer(_impl->GetShapeToMesh(), TopAbs_SHELL).More() )
5205           aNodePosition->shapeType = GEOM::SHELL;
5206         break;
5207       default:;
5208       }
5209     }
5210   }
5211   return aNodePosition;
5212 }
5213
5214 //=============================================================================
5215 /*!
5216  * \brief Return position of an element on shape
5217  */
5218 //=============================================================================
5219
5220 SMESH::ElementPosition SMESH_Mesh_i::GetElementPosition(CORBA::Long ElemID)
5221 {
5222   if ( _preMeshInfo )
5223     _preMeshInfo->FullLoadFromFile();
5224
5225   SMESH::ElementPosition anElementPosition;
5226   anElementPosition.shapeID = 0;
5227   anElementPosition.shapeType = GEOM::SHAPE;
5228
5229   SMESHDS_Mesh* mesh = _impl->GetMeshDS();
5230   if ( !mesh ) return anElementPosition;
5231
5232   if ( const SMDS_MeshElement* anElem = mesh->FindElement( ElemID ) )
5233   {
5234     anElementPosition.shapeID = anElem->getshapeId();
5235     const TopoDS_Shape& aSp = mesh->IndexToShape( anElem->getshapeId() );
5236     if ( !aSp.IsNull() ) {
5237       switch ( aSp.ShapeType() ) {
5238       case TopAbs_EDGE:
5239         anElementPosition.shapeType = GEOM::EDGE;
5240         break;
5241       case TopAbs_FACE:
5242         anElementPosition.shapeType = GEOM::FACE;
5243         break;
5244       case TopAbs_VERTEX:
5245         anElementPosition.shapeType = GEOM::VERTEX;
5246         break;
5247       case TopAbs_SOLID:
5248         anElementPosition.shapeType = GEOM::SOLID;
5249         break;
5250       case TopAbs_SHELL:
5251         anElementPosition.shapeType = GEOM::SHELL;
5252         break;
5253       default:;
5254       }
5255     }
5256   }
5257   return anElementPosition;
5258 }
5259
5260 //=============================================================================
5261 /*!
5262  * If given element is node return IDs of shape from position
5263  * If there is not node for given ID - return -1
5264  */
5265 //=============================================================================
5266
5267 CORBA::Long SMESH_Mesh_i::GetShapeID(const CORBA::Long id)
5268 {
5269   if ( _preMeshInfo )
5270     _preMeshInfo->FullLoadFromFile();
5271
5272   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5273   if ( aMeshDS == NULL )
5274     return -1;
5275
5276   // try to find node
5277   const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
5278   if(aNode) {
5279     return aNode->getshapeId();
5280   }
5281
5282   return -1;
5283 }
5284
5285
5286 //=============================================================================
5287 /*!
5288  * For given element return ID of result shape after
5289  * ::FindShape() from SMESH_MeshEditor
5290  * If there is not element for given ID - return -1
5291  */
5292 //=============================================================================
5293
5294 CORBA::Long SMESH_Mesh_i::GetShapeIDForElem(const CORBA::Long id)
5295 {
5296   if ( _preMeshInfo )
5297     _preMeshInfo->FullLoadFromFile();
5298
5299   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5300   if ( aMeshDS == NULL )
5301     return -1;
5302
5303   // try to find element
5304   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5305   if(!elem)
5306     return -1;
5307
5308   ::SMESH_MeshEditor aMeshEditor(_impl);
5309   int index = aMeshEditor.FindShape( elem );
5310   if(index>0)
5311     return index;
5312
5313   return -1;
5314 }
5315
5316
5317 //=============================================================================
5318 /*!
5319  * Return number of nodes for given element
5320  * If there is not element for given ID - return -1
5321  */
5322 //=============================================================================
5323
5324 CORBA::Long SMESH_Mesh_i::GetElemNbNodes(const CORBA::Long id)
5325 {
5326   if ( _preMeshInfo )
5327     _preMeshInfo->FullLoadFromFile();
5328
5329   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5330   if ( aMeshDS == NULL ) return -1;
5331   // try to find element
5332   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5333   if(!elem) return -1;
5334   return elem->NbNodes();
5335 }
5336
5337
5338 //=============================================================================
5339 /*!
5340  * Return ID of node by given index for given element
5341  * If there is not element for given ID - return -1
5342  * If there is not node for given index - return -2
5343  */
5344 //=============================================================================
5345
5346 CORBA::Long SMESH_Mesh_i::GetElemNode(const CORBA::Long id, const CORBA::Long index)
5347 {
5348   if ( _preMeshInfo )
5349     _preMeshInfo->FullLoadFromFile();
5350
5351   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5352   if ( aMeshDS == NULL ) return -1;
5353   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5354   if(!elem) return -1;
5355   if( index>=elem->NbNodes() || index<0 ) return -1;
5356   return elem->GetNode(index)->GetID();
5357 }
5358
5359 //=============================================================================
5360 /*!
5361  * Return IDs of nodes of given element
5362  */
5363 //=============================================================================
5364
5365 SMESH::long_array* SMESH_Mesh_i::GetElemNodes(const CORBA::Long id)
5366 {
5367   if ( _preMeshInfo )
5368     _preMeshInfo->FullLoadFromFile();
5369
5370   SMESH::long_array_var aResult = new SMESH::long_array();
5371   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() )
5372   {
5373     if ( const SMDS_MeshElement* elem = aMeshDS->FindElement(id) )
5374     {
5375       aResult->length( elem->NbNodes() );
5376       for ( CORBA::ULong i = 0; i < aResult->length(); ++i )
5377         if ( const SMDS_MeshNode* n = elem->GetNode( i ))
5378           aResult[ i ] = n->GetID();
5379     }
5380   }
5381   return aResult._retn();
5382 }
5383
5384 //=============================================================================
5385 /*!
5386  * Return true if given node is medium node
5387  * in given quadratic element
5388  */
5389 //=============================================================================
5390
5391 CORBA::Boolean SMESH_Mesh_i::IsMediumNode(const CORBA::Long ide, const CORBA::Long idn)
5392 {
5393   if ( _preMeshInfo )
5394     _preMeshInfo->FullLoadFromFile();
5395
5396   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5397   if ( aMeshDS == NULL ) return false;
5398   // try to find node
5399   const SMDS_MeshNode* aNode = aMeshDS->FindNode(idn);
5400   if(!aNode) return false;
5401   // try to find element
5402   const SMDS_MeshElement* elem = aMeshDS->FindElement(ide);
5403   if(!elem) return false;
5404
5405   return elem->IsMediumNode(aNode);
5406 }
5407
5408
5409 //=============================================================================
5410 /*!
5411  * Return true if given node is medium node
5412  * in one of quadratic elements
5413  */
5414 //=============================================================================
5415
5416 CORBA::Boolean SMESH_Mesh_i::IsMediumNodeOfAnyElem(const CORBA::Long idn,
5417                                                    SMESH::ElementType theElemType)
5418 {
5419   if ( _preMeshInfo )
5420     _preMeshInfo->FullLoadFromFile();
5421
5422   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5423   if ( aMeshDS == NULL ) return false;
5424
5425   // try to find node
5426   const SMDS_MeshNode* aNode = aMeshDS->FindNode(idn);
5427   if(!aNode) return false;
5428
5429   SMESH_MesherHelper aHelper( *(_impl) );
5430
5431   SMDSAbs_ElementType aType;
5432   if(theElemType==SMESH::EDGE) aType = SMDSAbs_Edge;
5433   else if(theElemType==SMESH::FACE) aType = SMDSAbs_Face;
5434   else if(theElemType==SMESH::VOLUME) aType = SMDSAbs_Volume;
5435   else aType = SMDSAbs_All;
5436
5437   return aHelper.IsMedium(aNode,aType);
5438 }
5439
5440
5441 //=============================================================================
5442 /*!
5443  * Return number of edges for given element
5444  */
5445 //=============================================================================
5446
5447 CORBA::Long SMESH_Mesh_i::ElemNbEdges(const CORBA::Long id)
5448 {
5449   if ( _preMeshInfo )
5450     _preMeshInfo->FullLoadFromFile();
5451
5452   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5453   if ( aMeshDS == NULL ) return -1;
5454   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5455   if(!elem) return -1;
5456   return elem->NbEdges();
5457 }
5458
5459
5460 //=============================================================================
5461 /*!
5462  * Return number of faces for given element
5463  */
5464 //=============================================================================
5465
5466 CORBA::Long SMESH_Mesh_i::ElemNbFaces(const CORBA::Long id)
5467 {
5468   if ( _preMeshInfo )
5469     _preMeshInfo->FullLoadFromFile();
5470
5471   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5472   if ( aMeshDS == NULL ) return -1;
5473   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5474   if(!elem) return -1;
5475   return elem->NbFaces();
5476 }
5477
5478 //================================================================================
5479 /*!
5480  * \brief Return nodes of given face (counted from zero) for given element.
5481  */
5482 //================================================================================
5483
5484 SMESH::long_array* SMESH_Mesh_i::GetElemFaceNodes(CORBA::Long  elemId,
5485                                                   CORBA::Short faceIndex)
5486 {
5487   if ( _preMeshInfo )
5488     _preMeshInfo->FullLoadFromFile();
5489
5490   SMESH::long_array_var aResult = new SMESH::long_array();
5491   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() )
5492   {
5493     if ( const SMDS_MeshElement* elem = aMeshDS->FindElement(elemId) )
5494     {
5495       SMDS_VolumeTool vtool( elem, /*skipCentralNodes = */false );
5496       if ( faceIndex < vtool.NbFaces() )
5497       {
5498         aResult->length( vtool.NbFaceNodes( faceIndex ));
5499         const SMDS_MeshNode** nn = vtool.GetFaceNodes( faceIndex );
5500         for ( CORBA::ULong i = 0; i < aResult->length(); ++i )
5501           aResult[ i ] = nn[ i ]->GetID();
5502       }
5503     }
5504   }
5505   return aResult._retn();
5506 }
5507
5508 //================================================================================
5509 /*!
5510  * \brief Return three components of normal of given mesh face.
5511  */
5512 //================================================================================
5513
5514 SMESH::double_array* SMESH_Mesh_i::GetFaceNormal(CORBA::Long    elemId,
5515                                                  CORBA::Boolean normalized)
5516 {
5517   if ( _preMeshInfo )
5518     _preMeshInfo->FullLoadFromFile();
5519
5520   SMESH::double_array_var aResult = new SMESH::double_array();
5521
5522   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5523   {
5524     gp_XYZ normal;
5525     if ( SMESH_MeshAlgos::FaceNormal( mesh->FindElement(elemId), normal, normalized ))
5526     {
5527       aResult->length( 3 );
5528       aResult[ 0 ] = normal.X();
5529       aResult[ 1 ] = normal.Y();
5530       aResult[ 2 ] = normal.Z();
5531     }
5532   }
5533   return aResult._retn();
5534 }
5535
5536 //================================================================================
5537 /*!
5538  * \brief Return an element based on all given nodes.
5539  */
5540 //================================================================================
5541
5542 CORBA::Long SMESH_Mesh_i::FindElementByNodes(const SMESH::long_array& nodes)
5543 {
5544   if ( _preMeshInfo )
5545     _preMeshInfo->FullLoadFromFile();
5546
5547   CORBA::Long elemID(0);
5548   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5549   {
5550     vector< const SMDS_MeshNode * > nn( nodes.length() );
5551     for ( CORBA::ULong i = 0; i < nodes.length(); ++i )
5552       if ( !( nn[i] = mesh->FindNode( nodes[i] )))
5553         return elemID;
5554
5555     const SMDS_MeshElement* elem = mesh->FindElement( nn, SMDSAbs_All, /*noMedium=*/false );
5556     if ( !elem && ( _impl->NbEdges  ( ORDER_QUADRATIC ) ||
5557                     _impl->NbFaces  ( ORDER_QUADRATIC ) ||
5558                     _impl->NbVolumes( ORDER_QUADRATIC )))
5559       elem = mesh->FindElement( nn, SMDSAbs_All, /*noMedium=*/true );
5560
5561     if ( elem ) elemID = CORBA::Long( elem->GetID() );
5562   }
5563   return elemID;
5564 }
5565
5566 //================================================================================
5567 /*!
5568  * \brief Return elements including all given nodes.
5569  */
5570 //================================================================================
5571
5572 SMESH::long_array* SMESH_Mesh_i::GetElementsByNodes(const SMESH::long_array& nodes,
5573                                                     SMESH::ElementType       elemType)
5574 {
5575   if ( _preMeshInfo )
5576     _preMeshInfo->FullLoadFromFile();
5577
5578   SMESH::long_array_var result = new SMESH::long_array();
5579
5580   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5581   {
5582     vector< const SMDS_MeshNode * > nn( nodes.length() );
5583     for ( CORBA::ULong i = 0; i < nodes.length(); ++i )
5584       nn[i] = mesh->FindNode( nodes[i] );
5585
5586     std::vector<const SMDS_MeshElement *> elems;
5587     mesh->GetElementsByNodes( nn, elems, (SMDSAbs_ElementType) elemType );
5588     result->length( elems.size() );
5589     for ( size_t i = 0; i < elems.size(); ++i )
5590       result[i] = elems[i]->GetID();
5591   }
5592   return result._retn();
5593 }
5594
5595 //=============================================================================
5596 /*!
5597  * Return true if given element is polygon
5598  */
5599 //=============================================================================
5600
5601 CORBA::Boolean SMESH_Mesh_i::IsPoly(const CORBA::Long id)
5602 {
5603   if ( _preMeshInfo )
5604     _preMeshInfo->FullLoadFromFile();
5605
5606   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5607   if ( aMeshDS == NULL ) return false;
5608   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5609   if(!elem) return false;
5610   return elem->IsPoly();
5611 }
5612
5613
5614 //=============================================================================
5615 /*!
5616  * Return true if given element is quadratic
5617  */
5618 //=============================================================================
5619
5620 CORBA::Boolean SMESH_Mesh_i::IsQuadratic(const CORBA::Long id)
5621 {
5622   if ( _preMeshInfo )
5623     _preMeshInfo->FullLoadFromFile();
5624
5625   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5626   if ( aMeshDS == NULL ) return false;
5627   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5628   if(!elem) return false;
5629   return elem->IsQuadratic();
5630 }
5631
5632 //=============================================================================
5633 /*!
5634  * Return diameter of ball discrete element or zero in case of an invalid \a id
5635  */
5636 //=============================================================================
5637
5638 CORBA::Double SMESH_Mesh_i::GetBallDiameter(CORBA::Long id)
5639 {
5640   if ( _preMeshInfo )
5641     _preMeshInfo->FullLoadFromFile();
5642
5643   if ( const SMDS_BallElement* ball =
5644        SMDS_Mesh::DownCast<SMDS_BallElement>( _impl->GetMeshDS()->FindElement( id )))
5645     return ball->GetDiameter();
5646
5647   return 0;
5648 }
5649
5650 //=============================================================================
5651 /*!
5652  * Return bary center for given element
5653  */
5654 //=============================================================================
5655
5656 SMESH::double_array* SMESH_Mesh_i::BaryCenter(const CORBA::Long id)
5657 {
5658   if ( _preMeshInfo )
5659     _preMeshInfo->FullLoadFromFile();
5660
5661   SMESH::double_array_var aResult = new SMESH::double_array();
5662   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5663   if ( aMeshDS == NULL )
5664     return aResult._retn();
5665
5666   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5667   if(!elem)
5668     return aResult._retn();
5669
5670   if(elem->GetType()==SMDSAbs_Volume) {
5671     SMDS_VolumeTool aTool;
5672     if(aTool.Set(elem)) {
5673       aResult->length(3);
5674       if (!aTool.GetBaryCenter( aResult[0], aResult[1], aResult[2]) )
5675         aResult->length(0);
5676     }
5677   }
5678   else {
5679     SMDS_ElemIteratorPtr anIt = elem->nodesIterator();
5680     int nbn = 0;
5681     double x=0., y=0., z=0.;
5682     for(; anIt->more(); ) {
5683       nbn++;
5684       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(anIt->next());
5685       x += aNode->X();
5686       y += aNode->Y();
5687       z += aNode->Z();
5688     }
5689     if(nbn>0) {
5690       // add coordinates
5691       aResult->length(3);
5692       aResult[0] = x/nbn;
5693       aResult[1] = y/nbn;
5694       aResult[2] = z/nbn;
5695     }
5696   }
5697
5698   return aResult._retn();
5699 }
5700
5701 //================================================================================
5702 /*!
5703  * \brief Create a group of elements preventing computation of a sub-shape
5704  */
5705 //================================================================================
5706
5707 SMESH::ListOfGroups*
5708 SMESH_Mesh_i::MakeGroupsOfBadInputElements( int         theSubShapeID,
5709                                             const char* theGroupName )
5710   throw ( SALOME::SALOME_Exception )
5711 {
5712   Unexpect aCatch(SALOME_SalomeException);
5713
5714   if ( !theGroupName || strlen( theGroupName) == 0 )
5715     THROW_SALOME_CORBA_EXCEPTION( "empty group name",SALOME::BAD_PARAM );
5716
5717   SMESH::ListOfGroups_var groups = new SMESH::ListOfGroups;
5718   ::SMESH_MeshEditor::ElemFeatures elemType;
5719
5720   // submesh by subshape id
5721   if ( !_impl->HasShapeToMesh() ) theSubShapeID = 1;
5722   if ( SMESH_subMesh * sm = _impl->GetSubMeshContaining( theSubShapeID ))
5723   {
5724     // compute error
5725     SMESH_ComputeErrorPtr error = sm->GetComputeError();
5726     if ( error && error->HasBadElems() )
5727     {
5728       // sort bad elements by type
5729       vector< const SMDS_MeshElement* > elemsByType[ SMDSAbs_NbElementTypes ];
5730       const list<const SMDS_MeshElement*>& badElems =
5731         static_cast<SMESH_BadInputElements*>( error.get() )->myBadElements;
5732       list<const SMDS_MeshElement*>::const_iterator elemIt  = badElems.begin();
5733       list<const SMDS_MeshElement*>::const_iterator elemEnd = badElems.end();
5734       for ( ; elemIt != elemEnd; ++elemIt )
5735       {
5736         const SMDS_MeshElement* elem = *elemIt;
5737         if ( !elem ) continue;
5738
5739         if ( elem->GetID() < 1 )
5740         {
5741           // elem is a temporary element, make a real element
5742           vector< const SMDS_MeshNode* > nodes;
5743           SMDS_NodeIteratorPtr nIt = elem->nodeIterator();
5744           while ( nIt->more() && elem )
5745           {
5746             nodes.push_back( nIt->next() );
5747             if ( nodes.back()->GetID() < 1 )
5748               elem = 0;  // a temporary element on temporary nodes
5749           }
5750           if ( elem )
5751           {
5752             ::SMESH_MeshEditor editor( _impl );
5753             elem = editor.AddElement( nodes, elemType.Init( elem ));
5754           }
5755         }
5756         if ( elem )
5757           elemsByType[ elem->GetType() ].push_back( elem );
5758       }
5759
5760       // how many groups to create?
5761       int nbTypes = 0;
5762       for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
5763         nbTypes += int( !elemsByType[ i ].empty() );
5764       groups->length( nbTypes );
5765
5766       // create groups
5767       for ( int i = 0, iG = -1; i < SMDSAbs_NbElementTypes; ++i )
5768       {
5769         vector< const SMDS_MeshElement* >& elems = elemsByType[ i ];
5770         if ( elems.empty() ) continue;
5771
5772         groups[ ++iG ] = createGroup( SMESH::ElementType(i), theGroupName );
5773         if ( _gen_i->CanPublishInStudy( groups[ iG ] ))
5774         {
5775           SMESH::SMESH_Mesh_var mesh = _this();
5776           SALOMEDS::SObject_wrap aSO =
5777             _gen_i->PublishGroup( mesh, groups[ iG ],
5778                                  GEOM::GEOM_Object::_nil(), theGroupName);
5779         }
5780         SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( groups[ iG ]);
5781         if ( !grp_i ) continue;
5782
5783         if ( SMESHDS_Group*  grpDS = dynamic_cast< SMESHDS_Group* >( grp_i->GetGroupDS() ))
5784           for ( size_t iE = 0; iE < elems.size(); ++iE )
5785             grpDS->SMDSGroup().Add( elems[ iE ]);
5786       }
5787     }
5788   }
5789
5790   return groups._retn();
5791 }
5792
5793 //=============================================================================
5794 /*!
5795  * Create and publish group servants if any groups were imported or created anyhow
5796  */
5797 //=============================================================================
5798
5799 void SMESH_Mesh_i::CreateGroupServants()
5800 {
5801   SMESH::SMESH_Mesh_var aMesh = _this();
5802
5803   set<int> addedIDs;
5804   ::SMESH_Mesh::GroupIteratorPtr groupIt = _impl->GetGroups();
5805   while ( groupIt->more() )
5806   {
5807     ::SMESH_Group* group = groupIt->next();
5808     int             anId = group->GetID();
5809
5810     map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.find(anId);
5811     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
5812       continue;
5813     addedIDs.insert( anId );
5814
5815     SMESH_GroupBase_i* aGroupImpl;
5816     TopoDS_Shape       shape;
5817     if ( SMESHDS_GroupOnGeom* groupOnGeom =
5818          dynamic_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() ))
5819     {
5820       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
5821       shape      = groupOnGeom->GetShape();
5822     }
5823     else {
5824       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
5825     }
5826
5827     SMESH::SMESH_GroupBase_var groupVar = aGroupImpl->_this();
5828     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( groupVar );
5829     aGroupImpl->Register();
5830
5831     // register CORBA object for persistence
5832     int nextId = _gen_i->RegisterObject( groupVar );
5833     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
5834     else        { nextId = 0; } // avoid "unused variable" warning in release mode
5835
5836     // publishing the groups in the study
5837     GEOM::GEOM_Object_var shapeVar = _gen_i->ShapeToGeomObject( shape );
5838     _gen_i->PublishGroup( aMesh, groupVar, shapeVar, group->GetName());
5839   }
5840
5841   if ( !addedIDs.empty() )
5842   {
5843     // python dump
5844     map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.begin();
5845     for ( int index = 0; i_grp != _mapGroups.end(); ++index, ++i_grp )
5846     {
5847       set<int>::iterator it = addedIDs.find( i_grp->first );
5848       if ( it != addedIDs.end() )
5849       {
5850         TPythonDump() << i_grp->second << " = " << aMesh << ".GetGroups()[ "<< index << " ]";
5851         addedIDs.erase( it );
5852         if ( addedIDs.empty() )
5853           break;
5854       }
5855     }
5856   }
5857 }
5858
5859 //=============================================================================
5860 /*!
5861  * \brief Return true if all sub-meshes are computed OK - to update an icon
5862  */
5863 //=============================================================================
5864
5865 bool SMESH_Mesh_i::IsComputedOK()
5866 {
5867   return _impl->IsComputedOK();
5868 }
5869
5870 //=============================================================================
5871 /*!
5872  * \brief Return groups cantained in _mapGroups by their IDs
5873  */
5874 //=============================================================================
5875
5876 SMESH::ListOfGroups* SMESH_Mesh_i::GetGroups(const list<int>& groupIDs) const
5877 {
5878   int nbGroups = groupIDs.size();
5879   SMESH::ListOfGroups_var aList = new SMESH::ListOfGroups();
5880   aList->length( nbGroups );
5881
5882   list<int>::const_iterator ids = groupIDs.begin();
5883   for ( nbGroups = 0; ids != groupIDs.end(); ++ids )
5884   {
5885     map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator it = _mapGroups.find( *ids );
5886     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
5887       aList[nbGroups++] = SMESH::SMESH_GroupBase::_duplicate( it->second );
5888   }
5889   aList->length( nbGroups );
5890   return aList._retn();
5891 }
5892
5893 //=============================================================================
5894 /*!
5895  * \brief Return information about imported file
5896  */
5897 //=============================================================================
5898
5899 SMESH::MedFileInfo* SMESH_Mesh_i::GetMEDFileInfo()
5900 {
5901   SMESH::MedFileInfo_var res( _medFileInfo );
5902   if ( !res.operator->() ) {
5903     res = new SMESH::MedFileInfo;
5904     res->fileName = "";
5905     res->fileSize = res->major = res->minor = res->release = -1;
5906   }
5907   return res._retn();
5908 }
5909
5910 //=======================================================================
5911 //function : FileInfoToString
5912 //purpose  : Persistence of file info
5913 //=======================================================================
5914
5915 std::string SMESH_Mesh_i::FileInfoToString()
5916 {
5917   std::string s;
5918   if ( &_medFileInfo.in() && _medFileInfo->fileName[0] )
5919   {
5920     s = SMESH_Comment( _medFileInfo->fileSize )
5921       << " " << _medFileInfo->major
5922       << " " << _medFileInfo->minor
5923       << " " << _medFileInfo->release
5924       << " " << _medFileInfo->fileName;
5925   }
5926   return s;
5927 }
5928
5929 //=======================================================================
5930 //function : FileInfoFromString
5931 //purpose  : Persistence of file info
5932 //=======================================================================
5933
5934 void SMESH_Mesh_i::FileInfoFromString(const std::string& info)
5935 {
5936   std::string size, major, minor, release, fileName;
5937   std::istringstream is(info);
5938   is >> size >> major >> minor >> release;
5939   fileName = info.data() + ( size.size()   + 1 +
5940                              major.size()  + 1 +
5941                              minor.size()  + 1 +
5942                              release.size()+ 1 );
5943
5944   _medFileInfo           = new SMESH::MedFileInfo();
5945   _medFileInfo->fileName = fileName.c_str();
5946   _medFileInfo->fileSize = atoi( size.c_str() );
5947   _medFileInfo->major    = atoi( major.c_str() );
5948   _medFileInfo->minor    = atoi( minor.c_str() );
5949   _medFileInfo->release  = atoi( release.c_str() );
5950 }
5951
5952 //=============================================================================
5953 /*!
5954  * \brief Pass names of mesh groups from study to mesh DS
5955  */
5956 //=============================================================================
5957
5958 void SMESH_Mesh_i::checkGroupNames()
5959 {
5960   int nbGrp = NbGroups();
5961   if ( !nbGrp )
5962     return;
5963
5964   SMESH::ListOfGroups* grpList = 0;
5965   // avoid dump of "GetGroups"
5966   {
5967     // store python dump into a local variable inside local scope
5968     SMESH::TPythonDump pDump; // do not delete this line of code
5969     grpList = GetGroups();
5970   }
5971
5972   for ( int gIndx = 0; gIndx < nbGrp; gIndx++ ) {
5973     SMESH::SMESH_GroupBase_ptr aGrp = (*grpList)[ gIndx ];
5974     if ( !aGrp )
5975       continue;
5976     SALOMEDS::SObject_wrap aGrpSO = _gen_i->ObjectToSObject( aGrp );
5977     if ( aGrpSO->_is_nil() )
5978       continue;
5979     // correct name of the mesh group if necessary
5980     const char* guiName = aGrpSO->GetName();
5981     if ( strcmp(guiName, aGrp->GetName()) )
5982       aGrp->SetName( guiName );
5983   }
5984 }
5985
5986 //=============================================================================
5987 /*!
5988  * \brief Set list of notebook variables used for Mesh operations separated by ":" symbol
5989  */
5990 //=============================================================================
5991 void SMESH_Mesh_i::SetParameters(const char* theParameters)
5992 {
5993   SMESH_Gen_i::GetSMESHGen()->UpdateParameters( CORBA::Object_var( _this() ).in(),
5994                                                 theParameters );
5995 }
5996
5997 //=============================================================================
5998 /*!
5999  * \brief Return list of notebook variables used for Mesh operations separated by ":" symbol
6000  */
6001 //=============================================================================
6002
6003 char* SMESH_Mesh_i::GetParameters()
6004 {
6005   return SMESH_Gen_i::GetSMESHGen()->GetParameters( SMESH::SMESH_Mesh_var( _this()) );
6006 }
6007
6008 //=============================================================================
6009 /*!
6010  * \brief Return list of notebook variables used for last Mesh operation
6011  */
6012 //=============================================================================
6013 SMESH::string_array* SMESH_Mesh_i::GetLastParameters()
6014 {
6015   SMESH::string_array_var aResult = new SMESH::string_array();
6016   SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen();
6017   if(gen) {
6018     CORBA::String_var aParameters = GetParameters();
6019     SALOMEDS::ListOfListOfStrings_var aSections = SMESH_Gen_i::getStudyServant()->ParseVariables(aParameters);
6020     if ( aSections->length() > 0 ) {
6021       SALOMEDS::ListOfStrings aVars = aSections[ aSections->length() - 1 ];
6022       aResult->length( aVars.length() );
6023       for ( CORBA::ULong i = 0;i < aVars.length(); i++ )
6024         aResult[i] = CORBA::string_dup( aVars[i] );
6025     }
6026   }
6027   return aResult._retn();
6028 }
6029
6030 //================================================================================
6031 /*!
6032  * \brief Return types of elements it contains
6033  */
6034 //================================================================================
6035
6036 SMESH::array_of_ElementType* SMESH_Mesh_i::GetTypes()
6037 {
6038   if ( _preMeshInfo )
6039     return _preMeshInfo->GetTypes();
6040
6041   SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType;
6042
6043   types->length( 5 );
6044   int nbTypes = 0;
6045   if (_impl->NbEdges())      types[nbTypes++] = SMESH::EDGE;
6046   if (_impl->NbFaces())      types[nbTypes++] = SMESH::FACE;
6047   if (_impl->NbVolumes())    types[nbTypes++] = SMESH::VOLUME;
6048   if (_impl->Nb0DElements()) types[nbTypes++] = SMESH::ELEM0D;
6049   if (_impl->NbBalls())      types[nbTypes++] = SMESH::BALL;
6050   if (_impl->NbNodes() &&
6051       nbTypes == 0 )         types[nbTypes++] = SMESH::NODE;
6052   types->length( nbTypes );
6053
6054   return types._retn();
6055 }
6056
6057 //================================================================================
6058 /*!
6059  * \brief Return self
6060  */
6061 //================================================================================
6062
6063 SMESH::SMESH_Mesh_ptr SMESH_Mesh_i::GetMesh()
6064 {
6065   return SMESH::SMESH_Mesh::_duplicate( _this() );
6066 }
6067
6068 //================================================================================
6069 /*!
6070  * \brief Return false if GetMeshInfo() return incorrect information that may
6071  *        happen if mesh data is not yet fully loaded from the file of study.
6072  * 
6073  * 
6074  */
6075 //================================================================================
6076
6077 bool SMESH_Mesh_i::IsMeshInfoCorrect()
6078 {
6079   return _preMeshInfo ? _preMeshInfo->IsMeshInfoCorrect() : true;
6080 }
6081
6082 //=============================================================================
6083 /*!
6084  * \brief Return number of mesh elements per each \a EntityType
6085  */
6086 //=============================================================================
6087
6088 SMESH::long_array* SMESH_Mesh_i::GetMeshInfo()
6089 {
6090   if ( _preMeshInfo )
6091     return _preMeshInfo->GetMeshInfo();
6092
6093   SMESH::long_array_var aRes = new SMESH::long_array();
6094   aRes->length(SMESH::Entity_Last);
6095   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
6096     aRes[i] = 0;
6097   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
6098   if (!aMeshDS)
6099     return aRes._retn();
6100   const SMDS_MeshInfo& aMeshInfo = aMeshDS->GetMeshInfo();
6101   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
6102     aRes[i] = aMeshInfo.NbEntities((SMDSAbs_EntityType)i);
6103   return aRes._retn();
6104 }
6105
6106 //=============================================================================
6107 /*!
6108  * \brief Return number of mesh elements per each \a ElementType
6109  */
6110 //=============================================================================
6111
6112 SMESH::long_array* SMESH_Mesh_i::GetNbElementsByType()
6113 {
6114   SMESH::long_array_var aRes = new SMESH::long_array();
6115   aRes->length(SMESH::NB_ELEMENT_TYPES);
6116   for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
6117     aRes[ i ] = 0;
6118
6119   const SMDS_MeshInfo* meshInfo = 0;
6120   if ( _preMeshInfo )
6121     meshInfo = _preMeshInfo;
6122   else if ( SMESHDS_Mesh* meshDS = _impl->GetMeshDS() )
6123     meshInfo = & meshDS->GetMeshInfo();
6124
6125   if (meshInfo)
6126     for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
6127       aRes[i] = meshInfo->NbElements((SMDSAbs_ElementType)i);
6128
6129   return aRes._retn();
6130 }
6131
6132 //=============================================================================
6133 /*
6134  * Collect statistic of mesh elements given by iterator
6135  */
6136 //=============================================================================
6137
6138 void SMESH_Mesh_i::CollectMeshInfo(const SMDS_ElemIteratorPtr theItr,
6139                                    SMESH::long_array&         theInfo)
6140 {
6141   if (!theItr) return;
6142   while (theItr->more())
6143     theInfo[ theItr->next()->GetEntityType() ]++;
6144 }
6145 //=============================================================================
6146 /*
6147  * Return mesh unstructed grid information.
6148  */
6149 //=============================================================================
6150
6151 SALOMEDS::TMPFile* SMESH_Mesh_i::GetVtkUgStream()
6152 {
6153   SALOMEDS::TMPFile_var SeqFile;
6154   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() ) {
6155     SMDS_UnstructuredGrid* aGrid = aMeshDS->GetGrid();
6156     if(aGrid) {
6157       vtkUnstructuredGridWriter* aWriter = vtkUnstructuredGridWriter::New();
6158       aWriter->WriteToOutputStringOn();
6159       aWriter->SetInputData(aGrid);
6160       aWriter->SetFileTypeToBinary();
6161       aWriter->Write();
6162       char* str = aWriter->GetOutputString();
6163       int size = aWriter->GetOutputStringLength();
6164
6165       //Allocate octet buffer of required size
6166       CORBA::Octet* OctetBuf = SALOMEDS::TMPFile::allocbuf(size);
6167       //Copy ostrstream content to the octet buffer
6168       memcpy(OctetBuf, str, size);
6169       //Create and return TMPFile
6170       SeqFile = new SALOMEDS::TMPFile(size, size, OctetBuf, 1);
6171       aWriter->Delete();
6172     }
6173   }
6174   return SeqFile._retn();
6175 }
6176
6177 //=============================================================================
6178 namespace /* Iterators used in SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_var obj,
6179            *                                             SMESH::ElementType        type) */
6180 {
6181   using namespace SMESH::Controls;
6182   //-----------------------------------------------------------------------------
6183   struct PredicateIterator : public SMDS_ElemIterator
6184   {
6185     SMDS_ElemIteratorPtr    _elemIter;
6186     PredicatePtr            _predicate;
6187     const SMDS_MeshElement* _elem;
6188     SMDSAbs_ElementType     _type;
6189
6190     PredicateIterator( SMDS_ElemIteratorPtr iterator,
6191                        PredicatePtr         predicate,
6192                        SMDSAbs_ElementType  type):
6193       _elemIter(iterator), _predicate(predicate), _type(type)
6194     {
6195       next();
6196     }
6197     virtual bool more()
6198     {
6199       return _elem;
6200     }
6201     virtual const SMDS_MeshElement* next()
6202     {
6203       const SMDS_MeshElement* res = _elem;
6204       _elem = 0;
6205       while ( _elemIter->more() && !_elem )
6206       {
6207         if ((_elem = _elemIter->next()) &&
6208             (( _type != SMDSAbs_All && _type != _elem->GetType() ) ||
6209              ( !_predicate->IsSatisfy( _elem->GetID() ))))
6210           _elem = 0;
6211       }
6212       return res;
6213     }
6214   };
6215
6216   //-----------------------------------------------------------------------------
6217   struct IDSourceIterator : public SMDS_ElemIterator
6218   {
6219     const CORBA::Long*        _idPtr;
6220     const CORBA::Long*        _idEndPtr;
6221     SMESH::long_array_var     _idArray;
6222     const SMDS_Mesh*          _mesh;
6223     const SMDSAbs_ElementType _type;
6224     const SMDS_MeshElement*   _elem;
6225
6226     IDSourceIterator( const SMDS_Mesh*    mesh,
6227                       const CORBA::Long*  ids,
6228                       const int           nbIds,
6229                       SMDSAbs_ElementType type):
6230       _idPtr( ids ), _idEndPtr( ids + nbIds ), _mesh( mesh ), _type( type ), _elem( 0 )
6231     {
6232       if ( _idPtr && nbIds && _mesh )
6233         next();
6234     }
6235     IDSourceIterator( const SMDS_Mesh*    mesh,
6236                       SMESH::long_array*  idArray,
6237                       SMDSAbs_ElementType type):
6238       _idPtr( 0 ), _idEndPtr( 0 ), _idArray( idArray), _mesh( mesh ), _type( type ), _elem( 0 )
6239     {
6240       if ( idArray && _mesh )
6241       {
6242         _idPtr    = &_idArray[0];
6243         _idEndPtr = _idPtr + _idArray->length();
6244         next();
6245       }
6246     }
6247     virtual bool more()
6248     {
6249       return _elem;
6250     }
6251     virtual const SMDS_MeshElement* next()
6252     {
6253       const SMDS_MeshElement* res = _elem;
6254       _elem = 0;
6255       while ( _idPtr < _idEndPtr && !_elem )
6256       {
6257         if ( _type == SMDSAbs_Node )
6258         {
6259           _elem = _mesh->FindNode( *_idPtr++ );
6260         }
6261         else if ((_elem = _mesh->FindElement( *_idPtr++ )) &&
6262                  (_elem->GetType() != _type && _type != SMDSAbs_All ))
6263         {
6264           _elem = 0;
6265         }
6266       }
6267       return res;
6268     }
6269   };
6270   //-----------------------------------------------------------------------------
6271
6272   struct NodeOfElemIterator : public SMDS_ElemIterator
6273   {
6274     TColStd_MapOfInteger    _checkedNodeIDs;
6275     SMDS_ElemIteratorPtr    _elemIter;
6276     SMDS_ElemIteratorPtr    _nodeIter;
6277     const SMDS_MeshElement* _node;
6278
6279     NodeOfElemIterator( SMDS_ElemIteratorPtr iter ): _elemIter( iter ), _node( 0 )
6280     {
6281       if ( _elemIter && _elemIter->more() )
6282       {
6283         _nodeIter = _elemIter->next()->nodesIterator();
6284         next();
6285       }
6286     }
6287     virtual bool more()
6288     {
6289       return _node;
6290     }
6291     virtual const SMDS_MeshElement* next()
6292     {
6293       const SMDS_MeshElement* res = _node;
6294       _node = 0;
6295       while ( !_node && ( _elemIter->more() || _nodeIter->more() ))
6296       {
6297         if ( _nodeIter->more() )
6298         {
6299           _node = _nodeIter->next();
6300           if ( !_checkedNodeIDs.Add( _node->GetID() ))
6301             _node = 0;
6302         }
6303         else
6304         {
6305           _nodeIter = _elemIter->next()->nodesIterator();
6306         }
6307       }
6308       return res;
6309     }
6310   };
6311 }
6312
6313 //=============================================================================
6314 /*
6315  * Return iterator on elements of given type in given object
6316  */
6317 //=============================================================================
6318
6319 SMDS_ElemIteratorPtr SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_ptr theObject,
6320                                                SMESH::ElementType        theType)
6321 {
6322   SMDS_ElemIteratorPtr  elemIt;
6323   bool                  typeOK = ( theType == SMESH::ALL );
6324   SMDSAbs_ElementType elemType = SMDSAbs_ElementType( theType );
6325
6326   SMESH::SMESH_Mesh_var meshVar = theObject->GetMesh();
6327   SMESH_Mesh_i*          mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( meshVar );
6328   if ( !mesh_i ) return elemIt;
6329   SMESHDS_Mesh*          meshDS = mesh_i->GetImpl().GetMeshDS();
6330
6331   if ( SMESH::DownCast<SMESH_Mesh_i*>( theObject ))
6332   {
6333     elemIt = meshDS->elementsIterator( elemType );
6334     typeOK = true;
6335   }
6336   else if ( SMESH_subMesh_i* submesh_i = SMESH::DownCast<SMESH_subMesh_i*>( theObject ))
6337   {
6338     SMESHDS_SubMesh* sm = ((SMESHDS_Mesh*) meshDS)->MeshElements( submesh_i->GetId() );
6339     if ( sm )
6340     {
6341       elemIt = sm->GetElements();
6342       if ( elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
6343       {
6344         typeOK = ( elemIt && elemIt->more() && elemIt->next()->GetType() == elemType );
6345         elemIt = typeOK ? sm->GetElements() : SMDS_ElemIteratorPtr();
6346       }
6347     }
6348   }
6349   else if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( theObject ))
6350   {
6351     SMESHDS_GroupBase* groupDS = group_i->GetGroupDS();
6352     if ( groupDS && ( elemType == groupDS->GetType()  ||
6353                       elemType == SMDSAbs_Node ||
6354                       elemType == SMDSAbs_All ))
6355     {
6356       elemIt = groupDS->GetElements();
6357       typeOK = ( groupDS->GetType() == elemType || elemType == SMDSAbs_All );
6358     }
6359   }
6360   else if ( SMESH::Filter_i* filter_i = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
6361   {
6362     if ( filter_i->GetElementType() == theType ||
6363          filter_i->GetElementType() == SMESH::ALL ||
6364          elemType == SMDSAbs_Node ||
6365          elemType == SMDSAbs_All)
6366     {
6367       SMESH::Predicate_i* pred_i = filter_i->GetPredicate_i();
6368       if ( pred_i && pred_i->GetPredicate() )
6369       {
6370         SMDSAbs_ElementType filterType = SMDSAbs_ElementType( filter_i->GetElementType() );
6371         SMDS_ElemIteratorPtr allElemIt = meshDS->elementsIterator( filterType );
6372         SMDSAbs_ElementType   iterType = elemType == SMDSAbs_Node ? filterType : elemType;
6373         elemIt = SMDS_ElemIteratorPtr
6374           ( new PredicateIterator( allElemIt, pred_i->GetPredicate(), iterType ));
6375         typeOK = ( elemType == SMDSAbs_Node ? filterType == SMDSAbs_Node : elemIt->more() );
6376       }
6377     }
6378   }
6379   else
6380   {
6381     SMESH::array_of_ElementType_var types = theObject->GetTypes();
6382     const bool                    isNodes = ( types->length() == 1 && types[0] == SMESH::NODE );
6383     if ( isNodes && elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
6384       return elemIt;
6385     SMDSAbs_ElementType iterType = isNodes ? SMDSAbs_Node : elemType;
6386     if ( SMESH_MeshEditor_i::IsTemporaryIDSource( theObject ))
6387     {
6388       int nbIds;
6389       if ( CORBA::Long* ids = SMESH_MeshEditor_i::GetTemporaryIDs( theObject, nbIds ))
6390         elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids, nbIds, iterType ));
6391     }
6392     else
6393     {
6394       SMESH::long_array_var ids = theObject->GetIDs();
6395       elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids._retn(), iterType ));
6396     }
6397     typeOK = ( isNodes == ( elemType == SMDSAbs_Node )) || ( elemType == SMDSAbs_All );
6398   }
6399
6400   if ( elemIt && elemIt->more() && !typeOK )
6401   {
6402     if ( elemType == SMDSAbs_Node )
6403     {
6404       elemIt = SMDS_ElemIteratorPtr( new NodeOfElemIterator( elemIt ));
6405     }
6406     else
6407     {
6408       elemIt = SMDS_ElemIteratorPtr();
6409     }
6410   }
6411   return elemIt;
6412 }
6413
6414 //=============================================================================
6415 namespace // Finding concurrent hypotheses
6416 //=============================================================================
6417 {
6418
6419 /*!
6420  * \brief mapping of mesh dimension into shape type
6421  */
6422 TopAbs_ShapeEnum shapeTypeByDim(const int theDim)
6423 {
6424   TopAbs_ShapeEnum aType = TopAbs_SOLID;
6425   switch ( theDim ) {
6426   case 0: aType = TopAbs_VERTEX; break;
6427   case 1: aType = TopAbs_EDGE; break;
6428   case 2: aType = TopAbs_FACE; break;
6429   case 3:
6430   default:aType = TopAbs_SOLID; break;
6431   }
6432   return aType;
6433 }
6434
6435 //-----------------------------------------------------------------------------
6436 /*!
6437  * \brief Internal structure used to find concurrent submeshes
6438  *
6439  * It represents a pair < submesh, concurrent dimension >, where
6440  * 'concurrent dimension' is dimension of shape where the submesh can concurrent
6441  *  with another submesh. In other words, it is dimension of a hypothesis assigned
6442  *  to submesh.
6443  */
6444 class SMESH_DimHyp
6445 {
6446  public:
6447   //! fields
6448   int _dim;    //!< a dimension the algo can build (concurrent dimension)
6449   int _ownDim; //!< dimension of shape of _subMesh (>=_dim)
6450   TopTools_MapOfShape  _shapeMap; //!< [sub-]shapes of dimension == _dim
6451   const SMESH_subMesh* _subMesh;
6452   list<const SMESHDS_Hypothesis*> _hypotheses; //!< algo is first, then its parameters
6453
6454   //-----------------------------------------------------------------------------
6455   // Return the algorithm
6456   const SMESH_Algo* GetAlgo() const
6457   { return _hypotheses.empty() ? 0 : dynamic_cast<const SMESH_Algo*>( _hypotheses.front() ); }
6458
6459   //-----------------------------------------------------------------------------
6460   //! Constructors
6461   SMESH_DimHyp(const SMESH_subMesh* theSubMesh,
6462                const int            theDim,
6463                const TopoDS_Shape&  theShape)
6464   {
6465     _subMesh = theSubMesh;
6466     SetShape( theDim, theShape );
6467   }
6468
6469   //-----------------------------------------------------------------------------
6470   //! set shape
6471   void SetShape(const int           theDim,
6472                 const TopoDS_Shape& theShape)
6473   {
6474     _dim = theDim;
6475     _ownDim = SMESH_Gen::GetShapeDim(theShape);
6476     if (_dim >= _ownDim)
6477       _shapeMap.Add( theShape );
6478     else {
6479       TopExp_Explorer anExp( theShape, shapeTypeByDim(theDim) );
6480       for( ; anExp.More(); anExp.Next() )
6481         _shapeMap.Add( anExp.Current() );
6482     }
6483   }
6484
6485   //-----------------------------------------------------------------------------
6486   //! Check sharing of sub-shapes
6487   static bool isShareSubShapes(const TopTools_MapOfShape& theToCheck,
6488                                const TopTools_MapOfShape& theToFind,
6489                                const TopAbs_ShapeEnum     theType)
6490   {
6491     bool isShared = false;
6492     TopTools_MapIteratorOfMapOfShape anItr( theToCheck );
6493     for (; !isShared && anItr.More(); anItr.Next() )
6494     {
6495       const TopoDS_Shape aSubSh = anItr.Key();
6496       // check for case when concurrent dimensions are same
6497       isShared = theToFind.Contains( aSubSh );
6498       // check for sub-shape with concurrent dimension
6499       TopExp_Explorer anExp( aSubSh, theType );
6500       for ( ; !isShared && anExp.More(); anExp.Next() )
6501         isShared = theToFind.Contains( anExp.Current() );
6502     }
6503     return isShared;
6504   }
6505
6506   //-----------------------------------------------------------------------------
6507   //! check algorithms
6508   static bool checkAlgo(const SMESHDS_Hypothesis* theA1,
6509                         const SMESHDS_Hypothesis* theA2)
6510   {
6511     if ( !theA1 || !theA2 ||
6512          theA1->GetType() == SMESHDS_Hypothesis::PARAM_ALGO ||
6513          theA2->GetType() == SMESHDS_Hypothesis::PARAM_ALGO )
6514       return false; // one of the hypothesis is not algorithm
6515     // check algorithm names (should be equal)
6516     return strcmp( theA1->GetName(), theA2->GetName() ) == 0;
6517   }
6518
6519
6520   //-----------------------------------------------------------------------------
6521   //! Check if sub-shape hypotheses are concurrent
6522   bool IsConcurrent(const SMESH_DimHyp* theOther) const
6523   {
6524     if ( _subMesh == theOther->_subMesh )
6525       return false; // same sub-shape - should not be
6526
6527     // if ( <own dim of either of submeshes> == <concurrent dim> &&
6528     //      any of the two submeshes is not on COMPOUND shape )
6529     //  -> no concurrency
6530     bool meIsCompound    = (_subMesh->GetSubMeshDS() &&
6531                             _subMesh->GetSubMeshDS()->IsComplexSubmesh());
6532     bool otherIsCompound = (theOther->_subMesh->GetSubMeshDS() &&
6533                             theOther->_subMesh->GetSubMeshDS()->IsComplexSubmesh());
6534     if ( (_ownDim == _dim  || theOther->_ownDim == _dim ) && (!meIsCompound || !otherIsCompound))
6535       return false;
6536
6537     bool checkSubShape = isShareSubShapes( _shapeMap, theOther->_shapeMap, shapeTypeByDim(_dim));
6538     if ( !checkSubShape )
6539       return false;
6540
6541     // check algorithms to be same
6542     const SMESH_Algo* a1 = this->GetAlgo();
6543     const SMESH_Algo* a2 = theOther->GetAlgo();
6544     bool isSame = checkAlgo( a1, a2 );
6545     if ( !isSame )
6546     {
6547       return true;
6548       // commented off for IPAL54678
6549       // if ( !a1 || !a2 )
6550       //   return false; // pb?
6551       // return a1->GetDim() == a2->GetDim(); // different algorithms of same dim -> concurrency !
6552     }
6553
6554     // check hypothesises for concurrence (skip first as algorithm)
6555     size_t nbSame = 0;
6556     // pointers should be same, because it is referened from mesh hypothesis partition
6557     list <const SMESHDS_Hypothesis*>::const_iterator hypIt = _hypotheses.begin();
6558     list <const SMESHDS_Hypothesis*>::const_iterator otheEndIt = theOther->_hypotheses.end();
6559     for ( hypIt++ /*skip first as algo*/; hypIt != _hypotheses.end(); hypIt++ )
6560       if ( find( theOther->_hypotheses.begin(), otheEndIt, *hypIt ) != otheEndIt )
6561         nbSame++;
6562     // the submeshes are concurrent if their algorithms has different parameters
6563     return nbSame != theOther->_hypotheses.size() - 1;
6564   }
6565
6566   // Return true if algorithm of this SMESH_DimHyp is used if no
6567   // sub-mesh order is imposed by the user
6568   bool IsHigherPriorityThan( const SMESH_DimHyp* theOther ) const
6569   {
6570     // NeedDiscreteBoundary() algo has a higher priority
6571     if ( this    ->GetAlgo()->NeedDiscreteBoundary() !=
6572          theOther->GetAlgo()->NeedDiscreteBoundary() )
6573       return !this->GetAlgo()->NeedDiscreteBoundary();
6574
6575     return ( this->_subMesh->GetId() < theOther->_subMesh->GetId() );
6576   }
6577
6578 }; // end of SMESH_DimHyp
6579 //-----------------------------------------------------------------------------
6580
6581 typedef list<const SMESH_DimHyp*> TDimHypList;
6582
6583 //-----------------------------------------------------------------------------
6584
6585 void addDimHypInstance(const int                               theDim,
6586                        const TopoDS_Shape&                     theShape,
6587                        const SMESH_Algo*                       theAlgo,
6588                        const SMESH_subMesh*                    theSubMesh,
6589                        const list <const SMESHDS_Hypothesis*>& theHypList,
6590                        TDimHypList*                            theDimHypListArr )
6591 {
6592   if ( !theAlgo->NeedDiscreteBoundary() &&
6593        theAlgo->NeedLowerHyps( theDim )) // IPAL54678
6594     return;
6595   TDimHypList& listOfdimHyp = theDimHypListArr[theDim];
6596   if ( listOfdimHyp.empty() || listOfdimHyp.back()->_subMesh != theSubMesh )
6597   {
6598     SMESH_DimHyp* dimHyp = new SMESH_DimHyp( theSubMesh, theDim, theShape );
6599     dimHyp->_hypotheses.push_front(theAlgo);
6600     listOfdimHyp.push_back( dimHyp );
6601   }
6602
6603   SMESH_DimHyp* dimHyp = const_cast<SMESH_DimHyp*>( listOfdimHyp.back() );
6604   dimHyp->_hypotheses.insert( dimHyp->_hypotheses.end(),
6605                               theHypList.begin(), theHypList.end() );
6606 }
6607
6608 //-----------------------------------------------------------------------------
6609 void addInOrderOfPriority( const SMESH_DimHyp* theDimHyp,
6610                            TDimHypList&        theListOfConcurr)
6611 {
6612   if ( theListOfConcurr.empty() )
6613   {
6614     theListOfConcurr.push_back( theDimHyp );
6615   }
6616   else
6617   {
6618     TDimHypList::iterator hypIt = theListOfConcurr.begin();
6619     while ( hypIt != theListOfConcurr.end() &&
6620             !theDimHyp->IsHigherPriorityThan( *hypIt ))
6621       ++hypIt;
6622     theListOfConcurr.insert( hypIt, theDimHyp );
6623   }
6624 }
6625
6626 //-----------------------------------------------------------------------------
6627 void findConcurrents(const SMESH_DimHyp* theDimHyp,
6628                      const TDimHypList&  theListOfDimHyp,
6629                      TDimHypList&        theListOfConcurrHyp,
6630                      set<int>&           theSetOfConcurrId )
6631 {
6632   TDimHypList::const_reverse_iterator rIt = theListOfDimHyp.rbegin();
6633   for ( ; rIt != theListOfDimHyp.rend(); rIt++ )
6634   {
6635     const SMESH_DimHyp* curDimHyp = *rIt;
6636     if ( curDimHyp == theDimHyp )
6637       break; // meet own dimHyp pointer in same dimension
6638
6639     if ( theDimHyp->IsConcurrent( curDimHyp ) &&
6640          theSetOfConcurrId.insert( curDimHyp->_subMesh->GetId() ).second )
6641     {
6642       addInOrderOfPriority( curDimHyp, theListOfConcurrHyp );
6643     }
6644   }
6645 }
6646
6647 //-----------------------------------------------------------------------------
6648 void unionLists(TListOfInt&       theListOfId,
6649                 TListOfListOfInt& theListOfListOfId,
6650                 const int         theIndx )
6651 {
6652   TListOfListOfInt::iterator it = theListOfListOfId.begin();
6653   for ( int i = 0; it != theListOfListOfId.end(); it++, i++ )
6654   {
6655     if ( i < theIndx )
6656       continue; //skip already treated lists
6657     // check if other list has any same submesh object
6658     TListOfInt& otherListOfId = *it;
6659     if ( find_first_of( theListOfId.begin(), theListOfId.end(),
6660                         otherListOfId.begin(), otherListOfId.end() ) == theListOfId.end() )
6661       continue;
6662
6663     // union two lists (from source into target)
6664     TListOfInt::iterator it2 = otherListOfId.begin();
6665     for ( ; it2 != otherListOfId.end(); it2++ ) {
6666       if ( find( theListOfId.begin(), theListOfId.end(), (*it2) ) == theListOfId.end() )
6667         theListOfId.push_back(*it2);
6668     }
6669     // clear source list
6670     otherListOfId.clear();
6671   }
6672 }
6673 //-----------------------------------------------------------------------------
6674
6675 //! free memory allocated for dimension-hypothesis objects
6676 void removeDimHyps( TDimHypList* theArrOfList )
6677 {
6678   for (int i = 0; i < 4; i++ ) {
6679     TDimHypList& listOfdimHyp = theArrOfList[i];
6680     TDimHypList::const_iterator it = listOfdimHyp.begin();
6681     for ( ; it != listOfdimHyp.end(); it++ )
6682       delete (*it);
6683   }
6684 }
6685
6686 //-----------------------------------------------------------------------------
6687 /*!
6688  * \brief find common submeshes with given submesh
6689  * \param theSubMeshList list of already collected submesh to check
6690  * \param theSubMesh given submesh to intersect with other
6691  * \param theCommonSubMeshes collected common submeshes
6692  */
6693 void findCommonSubMesh (list<const SMESH_subMesh*>& theSubMeshList,
6694                         const SMESH_subMesh*        theSubMesh,
6695                         set<const SMESH_subMesh*>&  theCommon )
6696 {
6697   if ( !theSubMesh )
6698     return;
6699   list<const SMESH_subMesh*>::const_iterator it = theSubMeshList.begin();
6700   for ( ; it != theSubMeshList.end(); it++ )
6701     theSubMesh->FindIntersection( *it, theCommon );
6702   theSubMeshList.push_back( theSubMesh );
6703   //theCommon.insert( theSubMesh );
6704 }
6705
6706 //-----------------------------------------------------------------------------
6707 bool isSubMeshInList ( int smID, const TListOfListOfInt& smLists )
6708 {
6709   TListOfListOfInt::const_iterator listsIt = smLists.begin();
6710   for ( ; listsIt != smLists.end(); ++listsIt )
6711   {
6712     const TListOfInt& smIDs = *listsIt;
6713     if ( std::find( smIDs.begin(), smIDs.end(), smID ) != smIDs.end() )
6714       return true;
6715   }
6716   return false;
6717 }
6718
6719 } // namespace
6720
6721 //=============================================================================
6722 /*!
6723  * \brief Return \c true if a meshing order not yet set for a concurrent sub-mesh
6724  */
6725 //=============================================================================
6726
6727 CORBA::Boolean SMESH_Mesh_i::IsUnorderedSubMesh(CORBA::Long submeshID)
6728 {
6729   TListOfListOfInt anOrder = GetImpl().GetMeshOrder(); // already defined order
6730   if ( isSubMeshInList( submeshID, anOrder ))
6731     return false;
6732
6733   TListOfListOfInt allConurrent = findConcurrentSubMeshes();
6734   return isSubMeshInList( submeshID, allConurrent );
6735 }
6736
6737 //=============================================================================
6738 /*!
6739  * \brief Return sub-mesh objects list in meshing order
6740  */
6741 //=============================================================================
6742
6743 SMESH::submesh_array_array* SMESH_Mesh_i::GetMeshOrder()
6744 {
6745   SMESH::submesh_array_array_var aResult = new SMESH::submesh_array_array();
6746
6747   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
6748   if ( !aMeshDS )
6749     return aResult._retn();
6750
6751   TListOfListOfInt      anOrder = GetImpl().GetMeshOrder(); // already defined order
6752   TListOfListOfInt allConurrent = findConcurrentSubMeshes();
6753   anOrder.splice( anOrder.end(), allConurrent );
6754
6755   int listIndx = 0;
6756   TListOfListOfInt::iterator listIt = anOrder.begin();
6757   for(; listIt != anOrder.end(); listIt++, listIndx++ )
6758     unionLists( *listIt,  anOrder, listIndx + 1 );
6759
6760   // convert submesh ids into interface instances
6761   //  and dump command into python
6762   convertMeshOrder( anOrder, aResult, false );
6763
6764   return aResult._retn();
6765 }
6766
6767 //=============================================================================
6768 /*!
6769  * \brief Finds concurrent sub-meshes
6770  */
6771 //=============================================================================
6772
6773 TListOfListOfInt SMESH_Mesh_i::findConcurrentSubMeshes()
6774 {
6775   TListOfListOfInt anOrder;
6776   ::SMESH_Mesh& mesh = GetImpl();
6777
6778   // collect submeshes and detect concurrent algorithms and hypothesises
6779   TDimHypList dimHypListArr[4]; // dimHyp list for each shape dimension
6780
6781   map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
6782   for ( ; i_sm != _mapSubMesh.end(); i_sm++ )
6783   {
6784     ::SMESH_subMesh* sm = (*i_sm).second;
6785     // shape of submesh
6786     const TopoDS_Shape& aSubMeshShape = sm->GetSubShape();
6787
6788     // list of assigned hypothesises
6789     const list <const SMESHDS_Hypothesis*>& hypList = mesh.GetHypothesisList(aSubMeshShape);
6790     // Find out dimensions where the submesh can be concurrent.
6791     // We define the dimensions by algo of each of hypotheses in hypList
6792     list <const SMESHDS_Hypothesis*>::const_iterator hypIt = hypList.begin();
6793     for( ; hypIt != hypList.end(); hypIt++ )
6794     {
6795       SMESH_Algo* anAlgo = 0;
6796       const SMESH_Hypothesis* hyp = dynamic_cast<const SMESH_Hypothesis*>(*hypIt);
6797       if ( hyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO )
6798         // hyp it-self is algo
6799         anAlgo = (SMESH_Algo*)dynamic_cast<const SMESH_Algo*>(hyp);
6800       else {
6801         // try to find algorithm with help of sub-shapes
6802         TopExp_Explorer anExp( aSubMeshShape, shapeTypeByDim(hyp->GetDim()) );
6803         for ( ; !anAlgo && anExp.More(); anExp.Next() )
6804           anAlgo = mesh.GetGen()->GetAlgo( mesh, anExp.Current() );
6805       }
6806       if (!anAlgo)
6807         continue; // no algorithm assigned to a current submesh
6808
6809       int dim = anAlgo->GetDim(); // top concurrent dimension (see comment to SMESH_DimHyp)
6810       // the submesh can concurrent at <dim> (or lower dims if !anAlgo->NeedDiscreteBoundary()
6811       // and !anAlgo->NeedLowerHyps( dim ))
6812
6813       // create instance of dimension-hypothesis for found concurrent dimension(s) and algorithm
6814       for ( int j = anAlgo->NeedDiscreteBoundary() ? dim : 1, jn = dim; j <= jn; j++ )
6815         addDimHypInstance( j, aSubMeshShape, anAlgo, sm, hypList, dimHypListArr );
6816     }
6817   } // end iterations on submesh
6818
6819     // iterate on created dimension-hypotheses and check for concurrents
6820   for ( int i = 0; i < 4; i++ )
6821   {
6822     const TDimHypList& listOfDimHyp = dimHypListArr[i];
6823     // check for concurrents in own and other dimensions (step-by-step)
6824     TDimHypList::const_iterator dhIt = listOfDimHyp.begin();
6825     for ( ; dhIt != listOfDimHyp.end(); dhIt++ )
6826     {
6827       const SMESH_DimHyp* dimHyp = *dhIt;
6828       TDimHypList listOfConcurr;
6829       set<int>    setOfConcurrIds;
6830       // looking for concurrents and collect into own list
6831       for ( int j = i; j < 4; j++ )
6832         findConcurrents( dimHyp, dimHypListArr[j], listOfConcurr, setOfConcurrIds );
6833       // check if any concurrents found
6834       if ( listOfConcurr.size() > 0 )
6835       {
6836         // add own submesh to list of concurrent
6837         addInOrderOfPriority( dimHyp, listOfConcurr );
6838         list<int> listOfConcurrIds;
6839         TDimHypList::iterator hypIt = listOfConcurr.begin();
6840         for ( ; hypIt != listOfConcurr.end(); ++hypIt )
6841           listOfConcurrIds.push_back( (*hypIt)->_subMesh->GetId() );
6842         anOrder.push_back( listOfConcurrIds );
6843       }
6844     }
6845   }
6846
6847   removeDimHyps(dimHypListArr);
6848
6849   // now, minimize the number of concurrent groups
6850   // Here we assume that lists of submeshes can have same submesh
6851   // in case of multi-dimension algorithms, as result
6852   //  list with common submesh has to be united into one list
6853   int listIndx = 0;
6854   TListOfListOfInt::iterator listIt = anOrder.begin();
6855   for(; listIt != anOrder.end(); listIt++, listIndx++ )
6856     unionLists( *listIt,  anOrder, listIndx + 1 );
6857
6858   return anOrder;
6859 }
6860
6861 //=============================================================================
6862 /*!
6863  * \brief Set submesh object order
6864  * \param theSubMeshArray submesh array order
6865  */
6866 //=============================================================================
6867
6868 ::CORBA::Boolean SMESH_Mesh_i::SetMeshOrder(const SMESH::submesh_array_array& theSubMeshArray)
6869 {
6870   if ( _preMeshInfo )
6871     _preMeshInfo->ForgetOrLoad();
6872
6873   bool res = false;
6874   ::SMESH_Mesh& mesh = GetImpl();
6875
6876   TPythonDump aPythonDump; // prevent dump of called methods
6877   aPythonDump << "isDone = " << SMESH::SMESH_Mesh_var(_this()) << ".SetMeshOrder( [ ";
6878
6879   TListOfListOfInt subMeshOrder;
6880   for ( int i = 0, n = theSubMeshArray.length(); i < n; i++ )
6881   {
6882     const SMESH::submesh_array& aSMArray = theSubMeshArray[i];
6883     TListOfInt subMeshIds;
6884     if ( i > 0 )
6885       aPythonDump << ", ";
6886     aPythonDump << "[ ";
6887     // Collect subMeshes which should be clear
6888     //  do it list-by-list, because modification of submesh order
6889     //  take effect between concurrent submeshes only
6890     set<const SMESH_subMesh*> subMeshToClear;
6891     list<const SMESH_subMesh*> subMeshList;
6892     for ( int j = 0, jn = aSMArray.length(); j < jn; j++ )
6893     {
6894       const SMESH::SMESH_subMesh_var subMesh = SMESH::SMESH_subMesh::_duplicate(aSMArray[j]);
6895       if ( j > 0 )
6896         aPythonDump << ", ";
6897       aPythonDump << subMesh;
6898       subMeshIds.push_back( subMesh->GetId() );
6899       // detect common parts of submeshes
6900       if ( _mapSubMesh.find(subMesh->GetId()) != _mapSubMesh.end() )
6901         findCommonSubMesh( subMeshList, _mapSubMesh[ subMesh->GetId() ], subMeshToClear );
6902     }
6903     aPythonDump << " ]";
6904     subMeshOrder.push_back( subMeshIds );
6905
6906     // clear collected sub-meshes
6907     set<const SMESH_subMesh*>::iterator clrIt = subMeshToClear.begin();
6908     for ( ; clrIt != subMeshToClear.end(); clrIt++ )
6909       if ( SMESH_subMesh* sm = (SMESH_subMesh*)*clrIt )
6910       {
6911         sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
6912         if ( SMESH_Algo* algo = sm->GetAlgo() ) // #16748
6913           sm->AlgoStateEngine( SMESH_subMesh::MODIF_HYP, algo ); // to clear a cached algo
6914       }
6915   }
6916   aPythonDump << " ])";
6917
6918   mesh.SetMeshOrder( subMeshOrder );
6919   res = true;
6920
6921   SMESH::SMESH_Mesh_var me = _this();
6922   _gen_i->UpdateIcons( me );
6923
6924   return res;
6925 }
6926
6927 //=============================================================================
6928 /*!
6929  * \brief Convert submesh ids into submesh interfaces
6930  */
6931 //=============================================================================
6932
6933 void SMESH_Mesh_i::convertMeshOrder (const TListOfListOfInt&     theIdsOrder,
6934                                      SMESH::submesh_array_array& theResOrder,
6935                                      const bool                  theIsDump)
6936 {
6937   int nbSet = theIdsOrder.size();
6938   TPythonDump aPythonDump; // prevent dump of called methods
6939   if ( theIsDump )
6940     aPythonDump << "[ ";
6941   theResOrder.length(nbSet);
6942   TListOfListOfInt::const_iterator it = theIdsOrder.begin();
6943   int listIndx = 0;
6944   for( ; it != theIdsOrder.end(); it++ )
6945   {
6946     // translate submesh identificators into submesh objects
6947     //  takeing into account real number of concurrent lists
6948     const TListOfInt& aSubOrder = (*it);
6949     if (!aSubOrder.size())
6950       continue;
6951     if ( theIsDump )
6952       aPythonDump << "[ ";
6953     // convert shape indices into interfaces
6954     SMESH::submesh_array_var aResSubSet = new SMESH::submesh_array();
6955     aResSubSet->length(aSubOrder.size());
6956     TListOfInt::const_iterator subIt = aSubOrder.begin();
6957     int j;
6958     for( j = 0; subIt != aSubOrder.end(); subIt++ )
6959     {
6960       if ( _mapSubMeshIor.find(*subIt) == _mapSubMeshIor.end() )
6961         continue;
6962       SMESH::SMESH_subMesh_var subMesh =
6963         SMESH::SMESH_subMesh::_duplicate( _mapSubMeshIor[*subIt] );
6964       if ( theIsDump ) {
6965         if ( j > 0 )
6966           aPythonDump << ", ";
6967         aPythonDump << subMesh;
6968       }
6969       aResSubSet[ j++ ] = subMesh;
6970     }
6971     if ( theIsDump )
6972       aPythonDump << " ]";
6973     if ( j > 1 )
6974       theResOrder[ listIndx++ ] = aResSubSet;
6975   }
6976   // correct number of lists
6977   theResOrder.length( listIndx );
6978
6979   if ( theIsDump ) {
6980     // finilise python dump
6981     aPythonDump << " ]";
6982     aPythonDump << " = " << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshOrder()";
6983   }
6984 }
6985
6986 namespace // utils used by SMESH_MeshPartDS
6987 {
6988   /*!
6989    * \brief Class used to access to protected data of SMDS_MeshInfo
6990    */
6991   struct TMeshInfo : public SMDS_MeshInfo
6992   {
6993     void Add(const SMDS_MeshElement* e) { SMDS_MeshInfo::addWithPoly( e ); }
6994   };
6995   /*!
6996    * \brief Element holing its ID only
6997    */
6998   struct TElemID : public SMDS_LinearEdge
6999   {
7000     TElemID(int ID) : SMDS_LinearEdge(0,0) { setID( ID ); }
7001   };
7002 }
7003
7004 //================================================================================
7005 //
7006 // Implementation of SMESH_MeshPartDS
7007 //
7008 SMESH_MeshPartDS::SMESH_MeshPartDS(SMESH::SMESH_IDSource_ptr meshPart):
7009   SMESHDS_Mesh( /*meshID=*/-1, /*isEmbeddedMode=*/true)
7010 {
7011   SMESH::SMESH_Mesh_var mesh = meshPart->GetMesh();
7012   SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
7013
7014   mesh_i->Load();
7015   _meshDS = mesh_i->GetImpl().GetMeshDS();
7016
7017   SetPersistentId( _meshDS->GetPersistentId() );
7018
7019   if ( mesh_i == SMESH::DownCast<SMESH_Mesh_i*>( meshPart ))
7020   {
7021     // <meshPart> is the whole mesh
7022     myInfo = _meshDS->GetMeshInfo(); // copy mesh info;
7023     // copy groups
7024     set<SMESHDS_GroupBase*>& myGroupSet = const_cast<set<SMESHDS_GroupBase*>&>( GetGroups() );
7025     myGroupSet = _meshDS->GetGroups();
7026   }
7027   else
7028   {
7029     TMeshInfo tmpInfo;
7030     SMESH::long_array_var           anIDs = meshPart->GetIDs();
7031     SMESH::array_of_ElementType_var types = meshPart->GetTypes();
7032     if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
7033     {
7034       for ( CORBA::ULong i=0; i < anIDs->length(); i++ )
7035         if ( const SMDS_MeshNode * n = _meshDS->FindNode( anIDs[i] ))
7036           if ( _elements[ SMDSAbs_Node ].insert( n ).second )
7037             tmpInfo.Add( n );
7038     }
7039     else
7040     {
7041       for ( CORBA::ULong i=0; i < anIDs->length(); i++ )
7042         if ( const SMDS_MeshElement * e = _meshDS->FindElement(anIDs[i]))
7043           if ( _elements[ e->GetType() ].insert( e ).second )
7044           {
7045             tmpInfo.Add( e );
7046             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7047             while ( nIt->more() )
7048             {
7049               const SMDS_MeshNode * n = (const SMDS_MeshNode*) nIt->next();
7050               if ( _elements[ SMDSAbs_Node ].insert( n ).second )
7051                 tmpInfo.Add( n );
7052             }
7053           }
7054     }
7055     myInfo = tmpInfo;
7056
7057     ShapeToMesh( _meshDS->ShapeToMesh() );
7058
7059     _meshDS = 0; // to enforce iteration on _elements and _nodes
7060   }
7061 }
7062 // -------------------------------------------------------------------------------------
7063 SMESH_MeshPartDS::SMESH_MeshPartDS(const std::list< const SMDS_MeshElement* > & meshPart):
7064   SMESHDS_Mesh( /*meshID=*/-1, /*isEmbeddedMode=*/true), _meshDS(0)
7065 {
7066   TMeshInfo tmpInfo;
7067   list< const SMDS_MeshElement* >::const_iterator partIt = meshPart.begin();
7068   for ( ; partIt != meshPart.end(); ++partIt )
7069     if ( const SMDS_MeshElement * e = *partIt )
7070       if ( _elements[ e->GetType() ].insert( e ).second )
7071       {
7072         tmpInfo.Add( e );
7073         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7074         while ( nIt->more() )
7075         {
7076           const SMDS_MeshNode * n = (const SMDS_MeshNode*) nIt->next();
7077           if ( _elements[ SMDSAbs_Node ].insert( n ).second )
7078             tmpInfo.Add( n );
7079         }
7080       }
7081   myInfo = tmpInfo;
7082 }
7083 // -------------------------------------------------------------------------------------
7084 const SMDS_MeshElement * SMESH_MeshPartDS::FindElement(int IDelem) const
7085 {
7086   if ( _meshDS ) return _meshDS->FindElement( IDelem );
7087
7088   TElemID elem( IDelem );
7089   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
7090     if ( !_elements[ iType ].empty() )
7091     {
7092       TIDSortedElemSet::const_iterator it = _elements[ iType ].find( &elem );
7093       if ( it != _elements[ iType ].end() )
7094         return *it;
7095     }
7096   return 0;
7097 }
7098 // -------------------------------------------------------------------------------------
7099 bool SMESH_MeshPartDS::HasNumerationHoles()
7100 {
7101   if ( _meshDS ) return _meshDS->HasNumerationHoles();
7102
7103   return ( MinNodeID() != 1 ||
7104            MaxNodeID() != NbNodes() ||
7105            MinElementID() != 1 ||
7106            MaxElementID() != NbElements() );
7107 }
7108 // -------------------------------------------------------------------------------------
7109 int SMESH_MeshPartDS::MaxNodeID() const
7110 {
7111   if ( _meshDS ) return _meshDS->MaxNodeID();
7112   return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].rbegin())->GetID();
7113 }
7114 // -------------------------------------------------------------------------------------
7115 int SMESH_MeshPartDS::MinNodeID() const
7116 {
7117   if ( _meshDS ) return _meshDS->MinNodeID();
7118   return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].begin())->GetID();
7119 }  
7120 // -------------------------------------------------------------------------------------
7121 int SMESH_MeshPartDS::MaxElementID() const
7122 {
7123   if ( _meshDS ) return _meshDS->MaxElementID();
7124   int maxID = 0;
7125   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
7126     if ( !_elements[ iType ].empty() )
7127       maxID = Max( maxID, (*_elements[ iType ].rbegin())->GetID() );
7128   return maxID;
7129 }
7130 // -------------------------------------------------------------------------------------
7131 int SMESH_MeshPartDS::MinElementID() const
7132 {
7133   if ( _meshDS ) return _meshDS->MinElementID();
7134   int minID = 0;
7135   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
7136     if ( !_elements[ iType ].empty() )
7137       minID = Min( minID, (*_elements[ iType ].begin())->GetID() );
7138   return minID;
7139 }
7140 // -------------------------------------------------------------------------------------
7141 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementGeomIterator(SMDSAbs_GeometryType geomType) const
7142 {
7143   if ( _meshDS ) return _meshDS->elementGeomIterator( geomType );
7144
7145   typedef SMDS_SetIterator
7146     <const SMDS_MeshElement*,
7147     TIDSortedElemSet::const_iterator,
7148     SMDS::SimpleAccessor<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator>,
7149     SMDS_MeshElement::GeomFilter
7150     > TIter;
7151
7152   SMDSAbs_ElementType type = SMDS_MeshCell::ElemType( geomType );
7153
7154   return SMDS_ElemIteratorPtr( new TIter( _elements[type].begin(),
7155                                           _elements[type].end(),
7156                                           SMDS_MeshElement::GeomFilter( geomType )));
7157 }
7158 // -------------------------------------------------------------------------------------
7159 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementEntityIterator(SMDSAbs_EntityType entity) const
7160 {
7161   if ( _meshDS ) return _meshDS->elementEntityIterator( entity );
7162
7163   typedef SMDS_SetIterator
7164     <const SMDS_MeshElement*,
7165     TIDSortedElemSet::const_iterator,
7166     SMDS::SimpleAccessor<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator>,
7167     SMDS_MeshElement::EntityFilter
7168     > TIter;
7169
7170   SMDSAbs_ElementType type = SMDS_MeshCell::ElemType( entity );
7171
7172   return SMDS_ElemIteratorPtr( new TIter( _elements[type].begin(),
7173                                           _elements[type].end(),
7174                                           SMDS_MeshElement::EntityFilter( entity )));
7175 }
7176 // -------------------------------------------------------------------------------------
7177 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementsIterator(SMDSAbs_ElementType type) const
7178 {
7179   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
7180   if ( type == SMDSAbs_All && !_meshDS )
7181   {
7182     typedef vector< SMDS_ElemIteratorPtr > TIterVec;
7183     TIterVec iterVec;
7184     for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
7185       if ( !_elements[i].empty() && i != SMDSAbs_Node )
7186         iterVec.push_back
7187           ( SMDS_ElemIteratorPtr( new TIter( _elements[i].begin(), _elements[i].end() )));
7188
7189     typedef SMDS_IteratorOnIterators<const SMDS_MeshElement*, TIterVec > TIterOnIters;
7190     return SMDS_ElemIteratorPtr( new TIterOnIters( iterVec ));
7191   }
7192   return _meshDS ? _meshDS->elementsIterator(type) : SMDS_ElemIteratorPtr
7193       ( new TIter( _elements[type].begin(), _elements[type].end() ));
7194 }
7195 // -------------------------------------------------------------------------------------
7196 #define _GET_ITER_DEFINE( iterType, methName, elem, elemType)                       \
7197   iterType SMESH_MeshPartDS::methName() const                 \
7198   {                                                                                 \
7199     typedef SMDS_SetIterator<const elem*, TIDSortedElemSet::const_iterator > TIter; \
7200     return _meshDS ? _meshDS->methName() : iterType                 \
7201       ( new TIter( _elements[elemType].begin(), _elements[elemType].end() ));       \
7202   }
7203 // -------------------------------------------------------------------------------------
7204 _GET_ITER_DEFINE( SMDS_NodeIteratorPtr, nodesIterator, SMDS_MeshNode, SMDSAbs_Node )
7205 _GET_ITER_DEFINE( SMDS_EdgeIteratorPtr, edgesIterator, SMDS_MeshEdge, SMDSAbs_Edge )
7206 _GET_ITER_DEFINE( SMDS_FaceIteratorPtr, facesIterator, SMDS_MeshFace, SMDSAbs_Face )
7207 _GET_ITER_DEFINE( SMDS_VolumeIteratorPtr, volumesIterator, SMDS_MeshVolume, SMDSAbs_Volume)
7208 #undef _GET_ITER_DEFINE
7209 //
7210 // END Implementation of SMESH_MeshPartDS
7211 //
7212 //================================================================================