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