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