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