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