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