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