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