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