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