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