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