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