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