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