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