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