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