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