Salome HOME
Implementation of the automatic breaking the link if the shape is modified or deleted
[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( theGeomObj );
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( geomGroup );
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( mainGO );
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   // for the SHAPER-STUDY: the geometry may be updated, so, add a warning icon
2245   if (_mainShapeTick != mainGO->GetTick()) {
2246     SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( me );
2247     if ( !meshSO->_is_nil())
2248       _gen_i->SetPixMap(meshSO, "ICON_SMESH_TREE_MESH_WARN");
2249   }
2250
2251   _mainShapeTick = mainGO->GetTick();
2252
2253   SMESHDS_Mesh * meshDS = _impl->GetMeshDS();
2254
2255   // store data of groups on geometry
2256   std::vector< TGroupOnGeomData > groupsData;
2257   const std::set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
2258   groupsData.reserve( groups.size() );
2259   std::set<SMESHDS_GroupBase*>::const_iterator g = groups.begin();
2260   for ( ; g != groups.end(); ++g )
2261   {
2262     if ( const SMESHDS_GroupOnGeom* group = dynamic_cast< SMESHDS_GroupOnGeom* >( *g ))
2263     {
2264       groupsData.push_back( TGroupOnGeomData( group ));
2265
2266       // get a new shape
2267       SMESH::SMESH_GroupOnGeom_var gog;
2268       std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.find( group->GetID() );
2269       if ( i_grp != _mapGroups.end() )
2270         gog = SMESH::SMESH_GroupOnGeom::_narrow( i_grp->second );
2271
2272       GEOM::GEOM_Object_var geom;
2273       if ( !gog->_is_nil() )
2274         geom = gog->GetShape();
2275       if ( !geom->_is_nil() )
2276       {
2277         CORBA::String_var ior = geomGen->GetStringFromIOR( geom );
2278         geomClient->RemoveShapeFromBuffer( ior.in() );
2279         groupsData.back()._shape = _gen_i->GeomObjectToShape( geom );
2280       }
2281     }
2282   }
2283   // store assigned hypotheses
2284   std::vector< pair< int, THypList > > ids2Hyps;
2285   const ShapeToHypothesis & hyps = meshDS->GetHypotheses();
2286   for ( ShapeToHypothesis::Iterator s2hyps( hyps ); s2hyps.More(); s2hyps.Next() )
2287   {
2288     const TopoDS_Shape& s = s2hyps.Key();
2289     const THypList&  hyps = s2hyps.ChangeValue();
2290     ids2Hyps.push_back( make_pair( meshDS->ShapeToIndex( s ), hyps ));
2291   }
2292
2293   // change shape to mesh
2294   int oldNbSubShapes = meshDS->MaxShapeIndex();
2295   _impl->ShapeToMesh( TopoDS_Shape() );
2296   _impl->ShapeToMesh( newShape );
2297
2298   // re-add shapes of geom groups
2299   std::list<TGeomGroupData>::iterator data = _geomGroupData.begin();
2300   for ( ; data != _geomGroupData.end(); ++data )
2301   {
2302     TopoDS_Shape newShape = newGroupShape( *data );
2303     if ( !newShape.IsNull() )
2304     {
2305       if ( meshDS->ShapeToIndex( newShape ) > 0 ) // a group reduced to one sub-shape
2306       {
2307         TopoDS_Compound compound;
2308         BRep_Builder().MakeCompound( compound );
2309         BRep_Builder().Add( compound, newShape );
2310         newShape = compound;
2311       }
2312       _impl->GetSubMesh( newShape );
2313     }
2314   }
2315   if ( oldNbSubShapes != meshDS->MaxShapeIndex() )
2316     THROW_SALOME_CORBA_EXCEPTION( "SMESH_Mesh_i::CheckGeomModif() bug",
2317                                   SALOME::INTERNAL_ERROR );
2318
2319   // re-assign hypotheses
2320   for ( size_t i = 0; i < ids2Hyps.size(); ++i )
2321   {
2322     const TopoDS_Shape& s = meshDS->IndexToShape( ids2Hyps[i].first );
2323     const THypList&  hyps = ids2Hyps[i].second;
2324     THypList::const_iterator h = hyps.begin();
2325     for ( ; h != hyps.end(); ++h )
2326       _impl->AddHypothesis( s, (*h)->GetID() );
2327   }
2328
2329   // restore groups on geometry
2330   for ( size_t i = 0; i < groupsData.size(); ++i )
2331   {
2332     const TGroupOnGeomData& data = groupsData[i];
2333     if ( data._shape.IsNull() )
2334       continue;
2335
2336     std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i2g = _mapGroups.find( data._oldID );
2337     if ( i2g == _mapGroups.end() ) continue;
2338
2339     SMESH_GroupBase_i* gr_i = SMESH::DownCast<SMESH_GroupBase_i*>( i2g->second );
2340     if ( !gr_i ) continue;
2341
2342     SMESH_Group* g = _impl->AddGroup( data._type, data._name.c_str(), data._oldID, data._shape );
2343     if ( !g )
2344       _mapGroups.erase( i2g );
2345     else
2346       g->GetGroupDS()->SetColor( data._color );
2347   }
2348
2349   // update _mapSubMesh
2350   std::map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
2351   for ( ; i_sm != _mapSubMesh.end(); ++i_sm )
2352     i_sm->second = _impl->GetSubMesh( meshDS->IndexToShape( i_sm->first ));
2353
2354 }
2355
2356 //=============================================================================
2357 /*!
2358  * \brief Update objects depending on changed geom groups
2359  *
2360  * NPAL16168: geometrical group edition from a submesh don't modify mesh computation
2361  * issue 0020210: Update of a smesh group after modification of the associated geom group
2362  */
2363 //=============================================================================
2364
2365 void SMESH_Mesh_i::CheckGeomGroupModif()
2366 {
2367   // remove sub-meshes referring a removed sub-shapes (if main shape still exists)
2368   SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
2369   GEOM::GEOM_Object_var  mainGO = GetShapeToMesh();
2370   SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( SMESH::SMESH_Mesh_var( _this() ));
2371   if ( !mainGO->_is_nil() && !meshSO->_is_nil() )
2372   {
2373     SALOMEDS::SObject_wrap rootSO, geomRefSO, geomSO;
2374     for ( CORBA::Long tag = SMESH::Tag_FirstSubMesh; tag <= SMESH::Tag_LastSubMesh; ++tag )
2375       if ( meshSO->FindSubObject( tag, rootSO.inout() ))
2376       {
2377         int nbValid = 0, nbRemoved = 0;
2378         SALOMEDS::ChildIterator_wrap chItr = _gen_i->getStudyServant()->NewChildIterator( rootSO );
2379         for ( ; chItr->More(); chItr->Next() )
2380         {
2381           SALOMEDS::SObject_wrap smSO = chItr->Value(); // sub-mesh SO
2382           if ( !smSO->_is_nil() &&
2383                smSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
2384                geomRefSO->ReferencedObject( geomSO.inout() )) // find geometry by reference
2385           {
2386             CORBA::Object_var  geomObj = _gen_i->SObjectToObject( geomSO );
2387             GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( geomObj );
2388             if ( !geom->_non_existent() )
2389             {
2390               ++nbValid;
2391               continue; // keep the sub-mesh
2392             }
2393           }
2394           CORBA::Object_var     smObj = _gen_i->SObjectToObject( smSO );
2395           SMESH::SMESH_subMesh_var sm = SMESH::SMESH_subMesh::_narrow( smObj );
2396           if ( !sm->_is_nil() && !sm->_non_existent() )
2397           {
2398             GEOM::GEOM_Object_var smGeom = sm->GetSubShape();
2399             if ( smGeom->_is_nil() )
2400             {
2401               RemoveSubMesh( sm );
2402               ++nbRemoved;
2403             }
2404           }
2405           else
2406           {
2407             if ( _preMeshInfo )
2408               _preMeshInfo->ForgetAllData(); // unknown hypothesis modified
2409             builder->RemoveObjectWithChildren( smSO ); // sub-shape removed before loading SMESH
2410             ++nbRemoved;
2411           }
2412         }
2413         if ( /*nbRemoved > 0 &&*/ nbValid == 0 )
2414           builder->RemoveObjectWithChildren( rootSO );
2415       }
2416   }
2417
2418   // check for removed sub-shapes and convert geom dependent groups into standalone ones
2419   std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
2420   while ( i_gr != _mapGroups.end())
2421   {
2422     SMESH::SMESH_GroupBase_ptr group = i_gr->second;
2423     ++i_gr;
2424     SALOMEDS::SObject_wrap        groupSO = _gen_i->ObjectToSObject( group ), refSO;
2425     SMESH::SMESH_GroupOnGeom_var   onGeom = SMESH::SMESH_GroupOnGeom::_narrow  ( group );
2426     SMESH::SMESH_GroupOnFilter_var onFilt = SMESH::SMESH_GroupOnFilter::_narrow( group );
2427     bool isValidGeom = false;
2428     if ( !onGeom->_is_nil() )
2429     {
2430       isValidGeom = ( ! GEOM::GEOM_Object_var( onGeom->GetShape() )->_is_nil() );
2431     }
2432     else if ( !onFilt->_is_nil() )
2433     {
2434       isValidGeom = isValidGeomFilter( onFilt->GetFilter() );
2435     }
2436     else // standalone
2437     {
2438       isValidGeom = ( !groupSO->_is_nil() &&
2439                       !groupSO->FindSubObject( SMESH::Tag_RefOnShape, refSO.inout() ));
2440     }
2441     if ( !isValidGeom )
2442     {
2443       if ( !IsLoaded() || group->IsEmpty() )
2444       {
2445         RemoveGroup( group );
2446       }
2447       else if ( !onGeom->_is_nil() || !onFilt->_is_nil() )
2448       {
2449         SMESH::SMESH_Group_var ( ConvertToStandalone( group ));
2450       }
2451       else // is it possible?
2452       {
2453         builder->RemoveObjectWithChildren( refSO );
2454       }
2455     }
2456   }
2457
2458
2459   if ( !_impl->HasShapeToMesh() ) return;
2460
2461   CORBA::Long nbEntities = NbNodes() + NbElements();
2462
2463   // Check if group contents changed
2464
2465   typedef map< string, TopoDS_Shape > TEntry2Geom;
2466   TEntry2Geom newGroupContents;
2467
2468   list<TGeomGroupData>::iterator
2469     data = _geomGroupData.begin(), dataEnd = _geomGroupData.end();
2470   for ( ; data != dataEnd; ++data )
2471   {
2472     pair< TEntry2Geom::iterator, bool > it_new =
2473       newGroupContents.insert( make_pair( data->_groupEntry, TopoDS_Shape() ));
2474     bool processedGroup    = !it_new.second;
2475     TopoDS_Shape& newShape = it_new.first->second;
2476     if ( !processedGroup )
2477       newShape = newGroupShape( *data );
2478     if ( newShape.IsNull() )
2479       continue; // no changes
2480
2481     if ( _preMeshInfo )
2482       _preMeshInfo->ForgetOrLoad();
2483
2484     if ( processedGroup ) { // update group indices
2485       list<TGeomGroupData>::iterator data2 = data;
2486       for ( --data2; data2->_groupEntry != data->_groupEntry; --data2) {}
2487       data->_indices = data2->_indices;
2488     }
2489
2490     // Update SMESH objects according to new GEOM group contents
2491
2492     SMESH::SMESH_subMesh_var submesh = SMESH::SMESH_subMesh::_narrow( data->_smeshObject );
2493     if ( !submesh->_is_nil() ) // -------------- Sub mesh ---------------------
2494     {
2495       int oldID = submesh->GetId();
2496       if ( !_mapSubMeshIor.count( oldID ))
2497         continue;
2498       TopoDS_Shape oldShape = _mapSubMesh[oldID]->GetSubShape();
2499
2500       // update hypotheses
2501       list <const SMESHDS_Hypothesis * > hyps = _impl->GetHypothesisList(oldShape);
2502       list <const SMESHDS_Hypothesis * >::iterator hypIt;
2503       for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2504       {
2505         _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
2506         _impl->AddHypothesis   ( newShape, (*hypIt)->GetID());
2507       }
2508       // care of submeshes
2509       SMESH_subMesh* newSubmesh = _impl->GetSubMesh( newShape );
2510       int newID = newSubmesh->GetId();
2511       if ( newID != oldID ) {
2512         _mapSubMesh   [ newID ] = newSubmesh;
2513         _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2514         _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2515         _mapSubMesh.   erase(oldID);
2516         _mapSubMesh_i. erase(oldID);
2517         _mapSubMeshIor.erase(oldID);
2518         _mapSubMesh_i [ newID ]->changeLocalId( newID );
2519       }
2520       continue;
2521     }
2522
2523     SMESH::SMESH_GroupOnGeom_var smeshGroup =
2524       SMESH::SMESH_GroupOnGeom::_narrow( data->_smeshObject );
2525     if ( !smeshGroup->_is_nil() ) // ------------ GROUP -----------------------
2526     {
2527       SMESH_GroupOnGeom_i* group_i = SMESH::DownCast<SMESH_GroupOnGeom_i*>( smeshGroup );
2528       if ( group_i ) {
2529         ::SMESH_Group* group = _impl->GetGroup( group_i->GetLocalID() );
2530         SMESHDS_GroupOnGeom* ds = static_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() );
2531         ds->SetShape( newShape );
2532       }
2533       continue;
2534     }
2535
2536     SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( data->_smeshObject );
2537     if ( !mesh->_is_nil() ) // -------------- MESH ----------------------------
2538     {
2539       // Remove groups and submeshes basing on removed sub-shapes
2540
2541       TopTools_MapOfShape newShapeMap;
2542       TopoDS_Iterator shapeIt( newShape );
2543       for ( ; shapeIt.More(); shapeIt.Next() )
2544         newShapeMap.Add( shapeIt.Value() );
2545
2546       SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
2547       for ( shapeIt.Initialize( meshDS->ShapeToMesh() ); shapeIt.More(); shapeIt.Next() )
2548       {
2549         if ( newShapeMap.Contains( shapeIt.Value() ))
2550           continue;
2551         TopTools_IndexedMapOfShape oldShapeMap;
2552         TopExp::MapShapes( shapeIt.Value(), oldShapeMap );
2553         for ( int i = 1; i <= oldShapeMap.Extent(); ++i )
2554         {
2555           const TopoDS_Shape& oldShape = oldShapeMap(i);
2556           int oldInd = meshDS->ShapeToIndex( oldShape );
2557           // -- submeshes --
2558           map<int, SMESH::SMESH_subMesh_ptr>::iterator i_smIor = _mapSubMeshIor.find( oldInd );
2559           if ( i_smIor != _mapSubMeshIor.end() ) {
2560             RemoveSubMesh( i_smIor->second ); // one submesh per shape index
2561           }
2562           // --- groups ---
2563           map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.begin();
2564           for ( ; i_grp != _mapGroups.end(); ++i_grp )
2565           {
2566             // check if a group bases on oldInd shape
2567             SMESHDS_GroupOnGeom* grpOnGeom = 0;
2568             if ( ::SMESH_Group* g = _impl->GetGroup( i_grp->first ))
2569               grpOnGeom = dynamic_cast<SMESHDS_GroupOnGeom*>( g->GetGroupDS() );
2570             if ( grpOnGeom && oldShape.IsSame( grpOnGeom->GetShape() ))
2571             { // remove
2572               RemoveGroup( i_grp->second ); // several groups can base on same shape
2573               i_grp = _mapGroups.begin(); // _mapGroups changed - restart iteration
2574             }
2575           }
2576         }
2577       }
2578       // Reassign hypotheses and update groups after setting the new shape to mesh
2579
2580       // collect anassigned hypotheses
2581       typedef list< pair< TIndexedShape, list<const SMESHDS_Hypothesis*> > > TShapeHypList;
2582       list <const SMESHDS_Hypothesis * >::const_iterator hypIt;
2583       TShapeHypList assignedHyps;
2584       for ( int i = 1; i <= meshDS->MaxShapeIndex(); ++i )
2585       {
2586         const TopoDS_Shape& oldShape = meshDS->IndexToShape(i);
2587         list<const SMESHDS_Hypothesis*> hyps = meshDS->GetHypothesis( oldShape );// copy
2588         if ( !hyps.empty() ) {
2589           assignedHyps.push_back( make_pair( TIndexedShape(i,oldShape), hyps ));
2590           for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2591             _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
2592         }
2593       }
2594       // collect shapes supporting groups
2595       typedef list < pair< TIndexedShape, SMDSAbs_ElementType > > TShapeTypeList;
2596       TShapeTypeList groupData;
2597       const set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
2598       set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2599       for ( ; grIt != groups.end(); ++grIt )
2600       {
2601         if ( SMESHDS_GroupOnGeom* gog = dynamic_cast<SMESHDS_GroupOnGeom*>( *grIt ))
2602           groupData.push_back
2603             ( make_pair( TIndexedShape( gog->GetID(),gog->GetShape()), gog->GetType()));
2604       }
2605       // set new shape to mesh -> DS of sub-meshes and geom groups is deleted
2606       _impl->Clear();
2607       _impl->ShapeToMesh( TopoDS_Shape() ); // IPAL52730
2608       _impl->ShapeToMesh( newShape );
2609
2610       // reassign hypotheses
2611       TShapeHypList::iterator indS_hyps = assignedHyps.begin();
2612       for ( ; indS_hyps != assignedHyps.end(); ++indS_hyps )
2613       {
2614         TIndexedShape&                   geom = indS_hyps->first;
2615         list<const SMESHDS_Hypothesis*>& hyps = indS_hyps->second;
2616         int oldID = geom._index;
2617         int newID = meshDS->ShapeToIndex( geom._shape );
2618         if ( oldID == 1 ) { // main shape
2619           newID = 1;
2620           geom._shape = newShape;
2621         }
2622         if ( !newID )
2623           continue;
2624         for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2625           _impl->AddHypothesis( geom._shape, (*hypIt)->GetID());
2626         // care of sub-meshes
2627         SMESH_subMesh* newSubmesh = _impl->GetSubMesh( geom._shape );
2628         if ( newID != oldID ) {
2629           _mapSubMesh   [ newID ] = newSubmesh;
2630           _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2631           _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2632           _mapSubMesh.   erase(oldID);
2633           _mapSubMesh_i. erase(oldID);
2634           _mapSubMeshIor.erase(oldID);
2635           _mapSubMesh_i [ newID ]->changeLocalId( newID );
2636         }
2637       }
2638       // recreate groups
2639       TShapeTypeList::iterator geomType = groupData.begin();
2640       for ( ; geomType != groupData.end(); ++geomType )
2641       {
2642         const TIndexedShape& geom = geomType->first;
2643         int oldID = geom._index;
2644         if ( _mapGroups.find( oldID ) == _mapGroups.end() )
2645           continue;
2646         // get group name
2647         SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( _mapGroups[oldID] );
2648         CORBA::String_var      name    = groupSO->GetName();
2649         // update
2650         if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>(_mapGroups[oldID]))
2651           if ( SMESH_Group* group = _impl->AddGroup( geomType->second, name.in(),
2652                                                      /*id=*/-1, geom._shape ))
2653             group_i->changeLocalId( group->GetID() );
2654       }
2655
2656       break; // everything has been updated
2657
2658     } // update mesh
2659   } // loop on group data
2660
2661   // Update icons
2662
2663   CORBA::Long newNbEntities = NbNodes() + NbElements();
2664   list< SALOMEDS::SObject_wrap > soToUpdateIcons;
2665   if ( newNbEntities != nbEntities )
2666   {
2667     // Add all SObjects with icons to soToUpdateIcons
2668     soToUpdateIcons.push_back( _gen_i->ObjectToSObject( _this() )); // mesh
2669
2670     for (map<int, SMESH::SMESH_subMesh_ptr>::iterator i_sm = _mapSubMeshIor.begin();
2671          i_sm != _mapSubMeshIor.end(); ++i_sm ) // submeshes
2672       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( i_sm->second ));
2673
2674     for ( map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
2675           i_gr != _mapGroups.end(); ++i_gr ) // groups
2676       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( i_gr->second ));
2677   }
2678
2679   list< SALOMEDS::SObject_wrap >::iterator so = soToUpdateIcons.begin();
2680   for ( ; so != soToUpdateIcons.end(); ++so )
2681     _gen_i->SetPixMap( *so, "ICON_SMESH_TREE_MESH_WARN" );
2682 }
2683
2684 //=============================================================================
2685 /*!
2686  * \brief Create standalone group from a group on geometry or filter
2687  */
2688 //=============================================================================
2689
2690 SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupBase_ptr theGroup )
2691   throw (SALOME::SALOME_Exception)
2692 {
2693   SMESH::SMESH_Group_var aGroup;
2694
2695   SMESH_TRY;
2696
2697   if ( _preMeshInfo )
2698     _preMeshInfo->FullLoadFromFile();
2699
2700   if ( theGroup->_is_nil() )
2701     return aGroup._retn();
2702
2703   SMESH_GroupBase_i* aGroupToRem = SMESH::DownCast<SMESH_GroupBase_i*>( theGroup );
2704   if ( !aGroupToRem )
2705     return aGroup._retn();
2706
2707   const bool isOnFilter = ( SMESH::DownCast< SMESH_GroupOnFilter_i* > ( theGroup ));
2708
2709   const int anId = aGroupToRem->GetLocalID();
2710   if ( !_impl->ConvertToStandalone( anId ) )
2711     return aGroup._retn();
2712   removeGeomGroupData( theGroup );
2713
2714   SMESH_GroupBase_i* aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
2715
2716   // remove old instance of group from own map
2717   { SMESH::SMESH_GroupBase_var var( _mapGroups[anId] ); } // decref CORBA object
2718   _mapGroups.erase( anId );
2719
2720   SALOMEDS::StudyBuilder_var builder;
2721   SALOMEDS::SObject_wrap     aGroupSO;
2722   SALOMEDS::Study_var        aStudy = SMESH_Gen_i::getStudyServant();
2723   if ( !aStudy->_is_nil() ) {
2724     builder  = aStudy->NewBuilder();
2725     aGroupSO = _gen_i->ObjectToSObject( theGroup );
2726     if ( !aGroupSO->_is_nil() )
2727     {
2728       // remove reference to geometry
2729       SALOMEDS::ChildIterator_wrap chItr = aStudy->NewChildIterator(aGroupSO);
2730       for ( ; chItr->More(); chItr->Next() )
2731       {
2732         // Remove group's child SObject
2733         SALOMEDS::SObject_wrap so = chItr->Value();
2734         builder->RemoveObject( so );
2735       }
2736       // Update Python script
2737       TPythonDump() << aGroupSO << " = " << SMESH::SMESH_Mesh_var(_this())
2738                     << ".ConvertToStandalone( " << aGroupSO << " )";
2739
2740       // change icon of Group on Filter
2741       if ( isOnFilter )
2742       {
2743         // SMESH::array_of_ElementType_var elemTypes = aGroupImpl->GetTypes();
2744         // const int isEmpty = ( elemTypes->length() == 0 );
2745         // if ( !isEmpty )
2746         {
2747           SALOMEDS::GenericAttribute_wrap anAttr =
2748             builder->FindOrCreateAttribute( aGroupSO, "AttributePixMap" );
2749           SALOMEDS::AttributePixMap_wrap pm = anAttr;
2750           pm->SetPixMap( "ICON_SMESH_TREE_GROUP" );
2751         }
2752       }
2753     }
2754   }
2755
2756   // remember new group in own map
2757   aGroup = SMESH::SMESH_Group::_narrow( aGroupImpl->_this() );
2758   _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
2759
2760   // register CORBA object for persistence
2761   _gen_i->RegisterObject( aGroup );
2762
2763   CORBA::String_var ior = _gen_i->GetORB()->object_to_string( aGroup );
2764   builder->SetIOR( aGroupSO, ior.in() ); //  == aGroup->Register();
2765   //aGroup->Register();
2766   aGroupToRem->UnRegister();
2767
2768   SMESH_CATCH( SMESH::throwCorbaException );
2769
2770   return aGroup._retn();
2771 }
2772
2773 //=============================================================================
2774 /*!
2775  *
2776  */
2777 //=============================================================================
2778
2779 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::createSubMesh( GEOM::GEOM_Object_ptr theSubShapeObject )
2780 {
2781   if(MYDEBUG) MESSAGE( "createSubMesh" );
2782   TopoDS_Shape  myLocSubShape = _gen_i->GeomObjectToShape(theSubShapeObject);
2783   ::SMESH_subMesh * mySubMesh = _impl->GetSubMesh(myLocSubShape);
2784   int               subMeshId = 0;
2785
2786   SMESH_subMesh_i * subMeshServant;
2787   if ( mySubMesh )
2788   {
2789     subMeshId = mySubMesh->GetId();
2790     subMeshServant = new SMESH_subMesh_i(myPOA, _gen_i, this, subMeshId);
2791   }
2792   else // "invalid sub-mesh"
2793   {
2794     // The invalid sub-mesh is created for the case where a valid sub-shape not found
2795     // by SMESH_Gen_i::CopyMeshWithGeom(). The invalid sub-mesh has GetId() < 0.
2796     if ( _mapSubMesh.empty() )
2797       subMeshId = -1;
2798     else
2799       subMeshId = _mapSubMesh.begin()->first - 1;
2800     subMeshServant = new SMESH_Invalid_subMesh_i(myPOA, _gen_i, this, subMeshId, theSubShapeObject);
2801   }
2802
2803   SMESH::SMESH_subMesh_var subMesh = subMeshServant->_this();
2804
2805   _mapSubMesh   [subMeshId] = mySubMesh;
2806   _mapSubMesh_i [subMeshId] = subMeshServant;
2807   _mapSubMeshIor[subMeshId] = SMESH::SMESH_subMesh::_duplicate( subMesh );
2808
2809   subMeshServant->Register();
2810
2811   // register CORBA object for persistence
2812   int nextId = _gen_i->RegisterObject( subMesh );
2813   if(MYDEBUG) { MESSAGE( "Add submesh to map with id = "<< nextId); }
2814   else        { nextId = 0; } // avoid "unused variable" warning
2815
2816   // to track changes of GEOM groups
2817   if ( subMeshId > 0 )
2818     addGeomGroupData( theSubShapeObject, subMesh );
2819
2820   return subMesh._retn();
2821 }
2822
2823 //=======================================================================
2824 //function : getSubMesh
2825 //purpose  :
2826 //=======================================================================
2827
2828 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::getSubMesh(int shapeID)
2829 {
2830   map<int, SMESH::SMESH_subMesh_ptr>::iterator it = _mapSubMeshIor.find( shapeID );
2831   if ( it == _mapSubMeshIor.end() )
2832     return SMESH::SMESH_subMesh::_nil();
2833
2834   return SMESH::SMESH_subMesh::_duplicate( (*it).second );
2835 }
2836
2837 //=============================================================================
2838 /*!
2839  *
2840  */
2841 //=============================================================================
2842
2843 bool SMESH_Mesh_i::removeSubMesh (SMESH::SMESH_subMesh_ptr theSubMesh,
2844                                   GEOM::GEOM_Object_ptr    theSubShapeObject )
2845 {
2846   bool isHypChanged = false;
2847   if ( theSubMesh->_is_nil() /*|| theSubShapeObject->_is_nil()*/ )
2848     return isHypChanged;
2849
2850   const int subMeshId = theSubMesh->GetId();
2851
2852   if ( theSubShapeObject->_is_nil() )  // not published shape (IPAL13617)
2853   {
2854     SMESH_subMesh* sm;
2855     if (( _mapSubMesh.count( subMeshId )) &&
2856         ( sm = _impl->GetSubMeshContaining( subMeshId )))
2857     {
2858       TopoDS_Shape S = sm->GetSubShape();
2859       if ( !S.IsNull() )
2860       {
2861         list<const SMESHDS_Hypothesis*> hyps = _impl->GetHypothesisList( S );
2862         isHypChanged = !hyps.empty();
2863         if ( isHypChanged && _preMeshInfo )
2864           _preMeshInfo->ForgetOrLoad();
2865         list<const SMESHDS_Hypothesis*>::const_iterator hyp = hyps.begin();
2866         for ( ; hyp != hyps.end(); ++hyp )
2867           _impl->RemoveHypothesis(S, (*hyp)->GetID());
2868       }
2869     }
2870   }
2871   else
2872   {
2873     try {
2874       SMESH::ListOfHypothesis_var aHypList = GetHypothesisList( theSubShapeObject );
2875       isHypChanged = ( aHypList->length() > 0 );
2876       for ( int i = 0, n = aHypList->length(); i < n; i++ ) {
2877         removeHypothesis( theSubShapeObject, aHypList[i] );
2878       }
2879     }
2880     catch( const SALOME::SALOME_Exception& ) {
2881       INFOS("SMESH_Mesh_i::removeSubMesh(): exception caught!");
2882     }
2883     removeGeomGroupData( theSubShapeObject );
2884   }
2885
2886   // remove a servant
2887   std::map<int, SMESH_subMesh_i*>::iterator id_smi = _mapSubMesh_i.find( subMeshId );
2888   if ( id_smi != _mapSubMesh_i.end() )
2889     id_smi->second->UnRegister();
2890
2891   // remove a CORBA object
2892   std::map<int, SMESH::SMESH_subMesh_ptr>::iterator id_smptr = _mapSubMeshIor.find( subMeshId );
2893   if ( id_smptr != _mapSubMeshIor.end() )
2894     SMESH::SMESH_subMesh_var( id_smptr->second );
2895
2896   _mapSubMesh.erase(subMeshId);
2897   _mapSubMesh_i.erase(subMeshId);
2898   _mapSubMeshIor.erase(subMeshId);
2899
2900   return isHypChanged;
2901 }
2902
2903 //=============================================================================
2904 /*!
2905  *
2906  */
2907 //=============================================================================
2908
2909 SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType        theElemType,
2910                                                       const char*               theName,
2911                                                       const int                 theID,
2912                                                       const TopoDS_Shape&       theShape,
2913                                                       const SMESH_PredicatePtr& thePredicate )
2914 {
2915   std::string newName;
2916   if ( !theName || !theName[0] )
2917   {
2918     std::set< std::string > presentNames;
2919     std::map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator i_gr = _mapGroups.begin();
2920     for ( ; i_gr != _mapGroups.end(); ++i_gr )
2921     {
2922       CORBA::String_var name = i_gr->second->GetName();
2923       presentNames.insert( name.in() );
2924     }
2925     do {
2926       newName = "noname_Group_" + SMESH_Comment( presentNames.size() + 1 );
2927     } while ( !presentNames.insert( newName ).second );
2928     theName = newName.c_str();
2929   }
2930   SMESH::SMESH_GroupBase_var aGroup;
2931   if ( SMESH_Group* g = _impl->AddGroup( (SMDSAbs_ElementType)theElemType, theName,
2932                                          theID, theShape, thePredicate ))
2933   {
2934     int anId = g->GetID();
2935     SMESH_GroupBase_i* aGroupImpl;
2936     if ( !theShape.IsNull() )
2937       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
2938     else if ( thePredicate )
2939       aGroupImpl = new SMESH_GroupOnFilter_i( SMESH_Gen_i::GetPOA(), this, anId );
2940     else
2941       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
2942
2943     aGroup = aGroupImpl->_this();
2944     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
2945     aGroupImpl->Register();
2946
2947     // register CORBA object for persistence
2948     int nextId = _gen_i->RegisterObject( aGroup );
2949     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
2950     else        { nextId = ( nextId > 0 ); } // avoid "unused variable" warning in release mode
2951
2952     // to track changes of GEOM groups
2953     if ( !theShape.IsNull() ) {
2954       GEOM::GEOM_Object_var geom = _gen_i->ShapeToGeomObject( theShape );
2955       addGeomGroupData( geom, aGroup );
2956     }
2957   }
2958   return aGroup._retn();
2959 }
2960
2961 //=============================================================================
2962 /*!
2963  * SMESH_Mesh_i::removeGroup
2964  *
2965  * Should be called by ~SMESH_Group_i()
2966  */
2967 //=============================================================================
2968
2969 void SMESH_Mesh_i::removeGroup( const int theId )
2970 {
2971   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::removeGroup()" );
2972   if ( _mapGroups.find( theId ) != _mapGroups.end() ) {
2973     SMESH::SMESH_GroupBase_var group = _mapGroups[theId];
2974     _mapGroups.erase( theId );
2975     removeGeomGroupData( group );
2976     if ( !_impl->RemoveGroup( theId ))
2977     {
2978       // it seems to be a call up from _impl caused by hyp modification (issue 0020918)
2979       RemoveGroup( group );
2980     }
2981     group->UnRegister();
2982   }
2983 }
2984
2985 //=============================================================================
2986 /*!
2987  *
2988  */
2989 //=============================================================================
2990
2991 SMESH::log_array * SMESH_Mesh_i::GetLog(CORBA::Boolean clearAfterGet)
2992   throw(SALOME::SALOME_Exception)
2993 {
2994   SMESH::log_array_var aLog;
2995
2996   SMESH_TRY;
2997   if ( _preMeshInfo )
2998     _preMeshInfo->FullLoadFromFile();
2999
3000   list < SMESHDS_Command * >logDS = _impl->GetLog();
3001   aLog = new SMESH::log_array;
3002   int indexLog = 0;
3003   int lg = logDS.size();
3004   SCRUTE(lg);
3005   aLog->length(lg);
3006   list < SMESHDS_Command * >::iterator its = logDS.begin();
3007   while(its != logDS.end()){
3008     SMESHDS_Command *com = *its;
3009     int comType = com->GetType();
3010     //SCRUTE(comType);
3011     int lgcom = com->GetNumber();
3012     //SCRUTE(lgcom);
3013     const list < int >&intList = com->GetIndexes();
3014     int inum = intList.size();
3015     //SCRUTE(inum);
3016     list < int >::const_iterator ii = intList.begin();
3017     const list < double >&coordList = com->GetCoords();
3018     int rnum = coordList.size();
3019     //SCRUTE(rnum);
3020     list < double >::const_iterator ir = coordList.begin();
3021     aLog[indexLog].commandType = comType;
3022     aLog[indexLog].number = lgcom;
3023     aLog[indexLog].coords.length(rnum);
3024     aLog[indexLog].indexes.length(inum);
3025     for(int i = 0; i < rnum; i++){
3026       aLog[indexLog].coords[i] = *ir;
3027       //MESSAGE(" "<<i<<" "<<ir.Value());
3028       ir++;
3029     }
3030     for(int i = 0; i < inum; i++){
3031       aLog[indexLog].indexes[i] = *ii;
3032       //MESSAGE(" "<<i<<" "<<ii.Value());
3033       ii++;
3034     }
3035     indexLog++;
3036     its++;
3037   }
3038   if(clearAfterGet)
3039     _impl->ClearLog();
3040
3041   SMESH_CATCH( SMESH::throwCorbaException );
3042
3043   return aLog._retn();
3044 }
3045
3046
3047 //=============================================================================
3048 /*!
3049  *
3050  */
3051 //=============================================================================
3052
3053 void SMESH_Mesh_i::ClearLog() throw(SALOME::SALOME_Exception)
3054 {
3055   SMESH_TRY;
3056   _impl->ClearLog();
3057   SMESH_CATCH( SMESH::throwCorbaException );
3058 }
3059
3060 //=============================================================================
3061 /*!
3062  *
3063  */
3064 //=============================================================================
3065
3066 CORBA::Long SMESH_Mesh_i::GetId()throw(SALOME::SALOME_Exception)
3067 {
3068   return _id;
3069 }
3070
3071 //=============================================================================
3072 namespace
3073 {
3074   //!< implementation of struct used to call methods of SMESH_Mesh_i from SMESH_Mesh
3075   // issue 0020918: groups removal is caused by hyp modification
3076   // issue 0021208: to forget not loaded mesh data at hyp modification
3077   struct TCallUp_i : public SMESH_Mesh::TCallUp
3078   {
3079     SMESH_Mesh_i* _mesh;
3080     TCallUp_i(SMESH_Mesh_i* mesh):_mesh(mesh) {}
3081     virtual void RemoveGroup (const int theGroupID) { _mesh->removeGroup( theGroupID ); }
3082     virtual void HypothesisModified (int theHypID)  { _mesh->onHypothesisModified( theHypID ); }
3083     virtual void Load ()                            { _mesh->Load(); }
3084   };
3085 }
3086
3087 //================================================================================
3088 /*!
3089  * \brief callback from _impl to forget not loaded mesh data (issue 0021208)
3090  */
3091 //================================================================================
3092
3093 void SMESH_Mesh_i::onHypothesisModified(int theHypID)
3094 {
3095   if ( _preMeshInfo )
3096     _preMeshInfo->ForgetOrLoad();
3097
3098   SMESH::SMESH_Mesh_var mesh = _this();
3099   _gen_i->UpdateIcons( mesh );
3100
3101   // mark a hypothesis as valid after edition
3102   SALOMEDS::SComponent_wrap smeshComp = _gen_i->PublishComponent();
3103   SALOMEDS::SObject_wrap hypRoot;
3104   if ( !smeshComp->_is_nil() && 
3105        smeshComp->FindSubObject( _gen_i->GetHypothesisRootTag(), hypRoot.inout() ))
3106   {
3107     SALOMEDS::ChildIterator_wrap anIter = _gen_i->getStudyServant()->NewChildIterator( hypRoot );
3108     for ( ; anIter->More(); anIter->Next() )
3109     {
3110       SALOMEDS::SObject_wrap    hypSO = anIter->Value();
3111       CORBA::Object_var           obj = _gen_i->SObjectToObject( hypSO );
3112       SMESH::SMESH_Hypothesis_var hyp = SMESH::SMESH_Hypothesis::_narrow( obj );
3113       if ( !hyp->_is_nil() && hyp->GetId() == theHypID )
3114         _gen_i->HighLightInvalid( hyp, false );
3115     }
3116   }
3117 }
3118
3119 //=============================================================================
3120 /*!
3121  *
3122  */
3123 //=============================================================================
3124
3125 void SMESH_Mesh_i::SetImpl(::SMESH_Mesh * impl)
3126 {
3127   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::SetImpl");
3128   _impl = impl;
3129   if ( _impl )
3130     _impl->SetCallUp( new TCallUp_i(this));
3131 }
3132
3133 //=============================================================================
3134 /*!
3135  *
3136  */
3137 //=============================================================================
3138
3139 ::SMESH_Mesh & SMESH_Mesh_i::GetImpl()
3140 {
3141   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::GetImpl()");
3142   return *_impl;
3143 }
3144
3145 //=============================================================================
3146 /*!
3147  * Return mesh editor
3148  */
3149 //=============================================================================
3150
3151 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditor()
3152   throw (SALOME::SALOME_Exception)
3153 {
3154   SMESH::SMESH_MeshEditor_var aMeshEdVar;
3155
3156   SMESH_TRY;
3157   if ( _preMeshInfo )
3158     _preMeshInfo->FullLoadFromFile();
3159
3160   // Create MeshEditor
3161   if ( !_editor )
3162     _editor = new SMESH_MeshEditor_i( this, false );
3163   aMeshEdVar = _editor->_this();
3164
3165   // Update Python script
3166   TPythonDump() << _editor << " = "
3167                 << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshEditor()";
3168
3169   SMESH_CATCH( SMESH::throwCorbaException );
3170
3171   return aMeshEdVar._retn();
3172 }
3173
3174 //=============================================================================
3175 /*!
3176  * Return mesh edition previewer
3177  */
3178 //=============================================================================
3179
3180 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditPreviewer()
3181   throw (SALOME::SALOME_Exception)
3182 {
3183   SMESH::SMESH_MeshEditor_var aMeshEdVar;
3184
3185   SMESH_TRY;
3186   if ( _preMeshInfo )
3187     _preMeshInfo->FullLoadFromFile();
3188
3189   if ( !_previewEditor )
3190     _previewEditor = new SMESH_MeshEditor_i( this, true );
3191   aMeshEdVar = _previewEditor->_this();
3192
3193   SMESH_CATCH( SMESH::throwCorbaException );
3194
3195   return aMeshEdVar._retn();
3196 }
3197
3198 //================================================================================
3199 /*!
3200  * \brief Return true if the mesh has been edited since a last total re-compute
3201  *        and those modifications may prevent successful partial re-compute
3202  */
3203 //================================================================================
3204
3205 CORBA::Boolean SMESH_Mesh_i::HasModificationsToDiscard() throw(SALOME::SALOME_Exception)
3206 {
3207   Unexpect aCatch(SALOME_SalomeException);
3208   return _impl->HasModificationsToDiscard();
3209 }
3210
3211 //================================================================================
3212 /*!
3213  * \brief Returns a random unique color
3214  */
3215 //================================================================================
3216
3217 static SALOMEDS::Color getUniqueColor( const std::list<SALOMEDS::Color>& theReservedColors )
3218 {
3219   const int MAX_ATTEMPTS = 100;
3220   int cnt = 0;
3221   double tolerance = 0.5;
3222   SALOMEDS::Color col;
3223
3224   bool ok = false;
3225   while ( !ok ) {
3226     // generate random color
3227     double red    = (double)rand() / RAND_MAX;
3228     double green  = (double)rand() / RAND_MAX;
3229     double blue   = (double)rand() / RAND_MAX;
3230     // check existence in the list of the existing colors
3231     bool matched = false;
3232     std::list<SALOMEDS::Color>::const_iterator it;
3233     for ( it = theReservedColors.begin(); it != theReservedColors.end() && !matched; ++it ) {
3234       SALOMEDS::Color color = *it;
3235       double tol = fabs( color.R - red ) + fabs( color.G - green ) + fabs( color.B  - blue  );
3236       matched = tol < tolerance;
3237     }
3238     if ( (cnt+1) % 20 == 0 ) tolerance = tolerance/2;
3239     ok = ( ++cnt == MAX_ATTEMPTS ) || !matched;
3240     col.R = red;
3241     col.G = green;
3242     col.B = blue;
3243   }
3244   return col;
3245 }
3246
3247 //=============================================================================
3248 /*!
3249  * Sets auto-color mode. If it is on, groups get unique random colors
3250  */
3251 //=============================================================================
3252
3253 void SMESH_Mesh_i::SetAutoColor(CORBA::Boolean theAutoColor) throw(SALOME::SALOME_Exception)
3254 {
3255   Unexpect aCatch(SALOME_SalomeException);
3256   _impl->SetAutoColor(theAutoColor);
3257
3258   TPythonDump pyDump; // not to dump group->SetColor() from below code
3259   pyDump << SMESH::SMESH_Mesh_var(_this()) <<".SetAutoColor( "<<theAutoColor<<" )";
3260
3261   std::list<SALOMEDS::Color> aReservedColors;
3262   map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.begin();
3263   for ( ; it != _mapGroups.end(); it++ ) {
3264     if ( CORBA::is_nil( it->second )) continue;
3265     SALOMEDS::Color aColor = getUniqueColor( aReservedColors );
3266     it->second->SetColor( aColor );
3267     aReservedColors.push_back( aColor );
3268   }
3269 }
3270
3271 //=============================================================================
3272 /*!
3273  * Returns true if auto-color mode is on
3274  */
3275 //=============================================================================
3276
3277 CORBA::Boolean SMESH_Mesh_i::GetAutoColor() throw(SALOME::SALOME_Exception)
3278 {
3279   Unexpect aCatch(SALOME_SalomeException);
3280   return _impl->GetAutoColor();
3281 }
3282
3283 //=============================================================================
3284 /*!
3285  *  Checks if there are groups with equal names
3286  */
3287 //=============================================================================
3288
3289 CORBA::Boolean SMESH_Mesh_i::HasDuplicatedGroupNamesMED()
3290 {
3291   return _impl->HasDuplicatedGroupNamesMED();
3292 }
3293
3294 //================================================================================
3295 /*!
3296  * \brief Care of a file before exporting mesh into it
3297  */
3298 //================================================================================
3299
3300 void SMESH_Mesh_i::PrepareForWriting (const char* file, bool overwrite)
3301 {
3302   SMESH_File aFile( file, false );
3303   SMESH_Comment msg;
3304   if ( aFile.exists() ) {
3305     // existing filesystem node
3306     if ( !aFile.isDirectory() ) {
3307       if ( aFile.openForWriting() ) {
3308         if ( overwrite && ! aFile.remove()) {
3309           msg << "Can't replace " << aFile.getName();
3310         }
3311       } else {
3312         msg << "Can't write into " << aFile.getName();
3313       }
3314     } else {
3315       msg << "Location " << aFile.getName() << " is not a file";
3316     }
3317   }
3318   else {
3319     // nonexisting file; check if it can be created
3320     if ( !aFile.openForWriting() ) {
3321       msg << "You cannot create the file "
3322           << aFile.getName()
3323           << ". Check the directory existence and access rights";
3324     }
3325     aFile.remove();
3326   }
3327
3328   if ( !msg.empty() )
3329   {
3330     msg << ".";
3331     THROW_SALOME_CORBA_EXCEPTION(msg.c_str(), SALOME::BAD_PARAM);
3332   }
3333 }
3334
3335 //================================================================================
3336 /*!
3337  * \brief Prepares a file for export and pass names of mesh groups from study to mesh DS
3338  *  \param file - file name
3339  *  \param overwrite - to erase the file or not
3340  *  \retval string - mesh name
3341  */
3342 //================================================================================
3343
3344 string SMESH_Mesh_i::prepareMeshNameAndGroups(const char*    file,
3345                                               CORBA::Boolean overwrite)
3346 {
3347   // Perform Export
3348   PrepareForWriting(file, overwrite);
3349   string aMeshName = "Mesh";
3350   SALOMEDS::Study_var aStudy = SMESH_Gen_i::getStudyServant();
3351   if ( !aStudy->_is_nil() ) {
3352     SALOMEDS::SObject_wrap aMeshSO = _gen_i->ObjectToSObject(  _this() );
3353     if ( !aMeshSO->_is_nil() ) {
3354       CORBA::String_var name = aMeshSO->GetName();
3355       aMeshName = name;
3356       // asv : 27.10.04 : fix of 6903: check for StudyLocked before adding attributes
3357       if ( !aStudy->GetProperties()->IsLocked() )
3358       {
3359         SALOMEDS::GenericAttribute_wrap anAttr;
3360         SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder();
3361         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeExternalFileDef");
3362         SALOMEDS::AttributeExternalFileDef_wrap aFileName = anAttr;
3363         ASSERT(!aFileName->_is_nil());
3364         aFileName->SetValue(file);
3365         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeFileType");
3366         SALOMEDS::AttributeFileType_wrap aFileType = anAttr;
3367         ASSERT(!aFileType->_is_nil());
3368         aFileType->SetValue("FICHIERMED");
3369       }
3370     }
3371   }
3372   // Update Python script
3373   // set name of mesh before export
3374   TPythonDump() << _gen_i << ".SetName("
3375                 << SMESH::SMESH_Mesh_var(_this()) << ", '" << aMeshName.c_str() << "')";
3376
3377   // check names of groups
3378   checkGroupNames();
3379
3380   return aMeshName;
3381 }
3382
3383 //================================================================================
3384 /*!
3385  * \brief Export to MED file
3386  */
3387 //================================================================================
3388
3389 void SMESH_Mesh_i::ExportMED(const char*        file,
3390                              CORBA::Boolean     auto_groups,
3391                              CORBA::Long        version,
3392                              CORBA::Boolean     overwrite,
3393                              CORBA::Boolean     autoDimension)
3394   throw(SALOME::SALOME_Exception)
3395 {
3396   //MESSAGE("MED minor version: "<< minor);
3397   SMESH_TRY;
3398   if ( _preMeshInfo )
3399     _preMeshInfo->FullLoadFromFile();
3400
3401   string aMeshName = prepareMeshNameAndGroups(file, overwrite);
3402   _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version, 0, autoDimension );
3403
3404   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportMED( r'"
3405                 << file << "', "
3406                 << "auto_groups=" <<auto_groups << ", "
3407                 << "minor=" << version <<  ", "
3408                 << "overwrite=" << overwrite << ", "
3409                 << "meshPart=None, "
3410                 << "autoDimension=" << autoDimension << " )";
3411
3412   SMESH_CATCH( SMESH::throwCorbaException );
3413 }
3414
3415 //================================================================================
3416 /*!
3417  * \brief Export a mesh to a SAUV file
3418  */
3419 //================================================================================
3420
3421 void SMESH_Mesh_i::ExportSAUV (const char* file,
3422                                CORBA::Boolean auto_groups)
3423   throw(SALOME::SALOME_Exception)
3424 {
3425   Unexpect aCatch(SALOME_SalomeException);
3426   if ( _preMeshInfo )
3427     _preMeshInfo->FullLoadFromFile();
3428
3429   string aMeshName = prepareMeshNameAndGroups(file, true);
3430   TPythonDump() << SMESH::SMESH_Mesh_var( _this())
3431                 << ".ExportSAUV( r'" << file << "', " << auto_groups << " )";
3432   _impl->ExportSAUV(file, aMeshName.c_str(), auto_groups);
3433 }
3434
3435
3436 //================================================================================
3437 /*!
3438  * \brief Export a mesh to a DAT file
3439  */
3440 //================================================================================
3441
3442 void SMESH_Mesh_i::ExportDAT (const char *file)
3443   throw(SALOME::SALOME_Exception)
3444 {
3445   Unexpect aCatch(SALOME_SalomeException);
3446   if ( _preMeshInfo )
3447     _preMeshInfo->FullLoadFromFile();
3448
3449   // Update Python script
3450   // check names of groups
3451   checkGroupNames();
3452   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportDAT( r'" << file << "' )";
3453
3454   // Perform Export
3455   PrepareForWriting(file);
3456   _impl->ExportDAT(file);
3457 }
3458
3459 //================================================================================
3460 /*!
3461  * \brief Export a mesh to an UNV file
3462  */
3463 //================================================================================
3464
3465 void SMESH_Mesh_i::ExportUNV (const char *file)
3466   throw(SALOME::SALOME_Exception)
3467 {
3468   Unexpect aCatch(SALOME_SalomeException);
3469   if ( _preMeshInfo )
3470     _preMeshInfo->FullLoadFromFile();
3471
3472   // Update Python script
3473   // check names of groups
3474   checkGroupNames();
3475   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportUNV( r'" << file << "' )";
3476
3477   // Perform Export
3478   PrepareForWriting(file);
3479   _impl->ExportUNV(file);
3480 }
3481
3482 //================================================================================
3483 /*!
3484  * \brief Export a mesh to an STL file
3485  */
3486 //================================================================================
3487
3488 void SMESH_Mesh_i::ExportSTL (const char *file, const bool isascii)
3489   throw(SALOME::SALOME_Exception)
3490 {
3491   Unexpect aCatch(SALOME_SalomeException);
3492   if ( _preMeshInfo )
3493     _preMeshInfo->FullLoadFromFile();
3494
3495   // Update Python script
3496   // check names of groups
3497   checkGroupNames();
3498   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
3499                 << ".ExportSTL( r'" << file << "', " << isascii << " )";
3500
3501   CORBA::String_var name;
3502   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( _this() );
3503   if ( !so->_is_nil() )
3504     name = so->GetName();
3505
3506   // Perform Export
3507   PrepareForWriting( file );
3508   _impl->ExportSTL( file, isascii, name.in() );
3509 }
3510
3511 //================================================================================
3512 /*!
3513  * \brief Export a part of mesh to a med file
3514  */
3515 //================================================================================
3516
3517 void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
3518                                    const char*               file,
3519                                    CORBA::Boolean            auto_groups,
3520                                    CORBA::Long               version,
3521                                    CORBA::Boolean            overwrite,
3522                                    CORBA::Boolean            autoDimension,
3523                                    const GEOM::ListOfFields& fields,
3524                                    const char*               geomAssocFields,
3525                                    CORBA::Double             ZTolerance)
3526   throw (SALOME::SALOME_Exception)
3527 {
3528   MESSAGE("MED version: "<< version);
3529   SMESH_TRY;
3530   if ( _preMeshInfo )
3531     _preMeshInfo->FullLoadFromFile();
3532
3533   // check fields
3534   bool have0dField = false;
3535   if ( fields.length() > 0 )
3536   {
3537     GEOM::GEOM_Object_var shapeToMesh = GetShapeToMesh();
3538     if ( shapeToMesh->_is_nil() )
3539       THROW_SALOME_CORBA_EXCEPTION( "No shape to mesh", SALOME::INTERNAL_ERROR );
3540
3541     for ( size_t i = 0; i < fields.length(); ++i )
3542     {
3543       if ( fields[i]->GetDataType() == GEOM::FDT_String )
3544         THROW_SALOME_CORBA_EXCEPTION
3545           ( "Export of string fields is not supported", SALOME::BAD_PARAM);
3546       GEOM::GEOM_Object_var fieldShape = fields[i]->GetShape();
3547       if ( fieldShape->_is_nil() )
3548         THROW_SALOME_CORBA_EXCEPTION( "Null shape under a field", SALOME::INTERNAL_ERROR );
3549       if ( !fieldShape->IsSame( shapeToMesh ) )
3550         THROW_SALOME_CORBA_EXCEPTION
3551           ( "Field defined not on shape", SALOME::BAD_PARAM);
3552       if ( fields[i]->GetDimension() == 0 )
3553         have0dField = true;
3554     }
3555     if ( geomAssocFields )
3556       for ( int i = 0; geomAssocFields[i]; ++i )
3557         switch ( geomAssocFields[i] ) {
3558         case 'v':case 'e':case 'f':case 's': break;
3559         case 'V':case 'E':case 'F':case 'S': break;
3560         default: THROW_SALOME_CORBA_EXCEPTION
3561             ( "geomAssocFields can include only [vefs] characters", SALOME::BAD_PARAM);
3562         }
3563   }
3564
3565   SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
3566
3567   // write mesh
3568
3569   string aMeshName = "Mesh";
3570   SMESHUtils::Deleter< SMESH_MeshPartDS > tmpDSDeleter(0);
3571   if ( CORBA::is_nil( meshPart ) ||
3572        SMESH::DownCast< SMESH_Mesh_i* >( meshPart ))
3573   {
3574     aMeshName = prepareMeshNameAndGroups(file, overwrite);
3575     _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version,
3576                       0, autoDimension, /*addODOnVertices=*/have0dField,
3577                       ZTolerance);
3578     meshDS = _impl->GetMeshDS();
3579   }
3580   else
3581   {
3582     if ( _preMeshInfo )
3583       _preMeshInfo->FullLoadFromFile();
3584
3585     PrepareForWriting(file, overwrite);
3586
3587     SALOMEDS::SObject_wrap SO = _gen_i->ObjectToSObject( meshPart );
3588     if ( !SO->_is_nil() ) {
3589       CORBA::String_var name = SO->GetName();
3590       aMeshName = name;
3591     }
3592
3593     SMESH_MeshPartDS* partDS = new SMESH_MeshPartDS( meshPart );
3594     _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version,
3595                       partDS, autoDimension, /*addODOnVertices=*/have0dField, ZTolerance);
3596     meshDS = tmpDSDeleter._obj = partDS;
3597   }
3598
3599   // write fields
3600
3601   if ( _impl->HasShapeToMesh() )
3602   {
3603     DriverMED_W_Field fieldWriter;
3604     fieldWriter.SetFile( file );
3605     fieldWriter.SetMeshName( aMeshName );
3606     fieldWriter.AddODOnVertices( have0dField );
3607
3608     exportMEDFields( fieldWriter, meshDS, fields, geomAssocFields );
3609   }
3610
3611   // dump
3612   GEOM::ListOfGBO_var goList = new GEOM::ListOfGBO;
3613   goList->length( fields.length() );
3614   for ( size_t i = 0; i < fields.length(); ++i )
3615   {
3616     GEOM::GEOM_BaseObject_var gbo = GEOM::GEOM_BaseObject::_narrow( fields[i] );
3617     goList[i] = gbo;
3618   }
3619   TPythonDump() << _this() << ".ExportPartToMED( "
3620                 << meshPart << ", r'"
3621                 << file << "', "
3622                 << auto_groups << ", "
3623                 << version << ", "
3624                 << overwrite << ", "
3625                 << autoDimension << ", "
3626                 << goList << ", '"
3627                 << ( geomAssocFields ? geomAssocFields : "" ) << "',"
3628                 << TVar( ZTolerance )
3629                 << " )";
3630
3631   SMESH_CATCH( SMESH::throwCorbaException );
3632 }
3633
3634 //================================================================================
3635 /*!
3636  * Write GEOM fields to MED file
3637  */
3638 //================================================================================
3639
3640 void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
3641                                     SMESHDS_Mesh*             meshDS,
3642                                     const GEOM::ListOfFields& fields,
3643                                     const char*               geomAssocFields)
3644 {
3645 #define METH "SMESH_Mesh_i::exportMEDFields() "
3646
3647   if (( fields.length() < 1 ) &&
3648       ( !geomAssocFields || !geomAssocFields[0] ))
3649     return;
3650
3651   std::vector< std::vector< double > > dblVals;
3652   std::vector< std::vector< int > >    intVals;
3653   std::vector< int >                   subIdsByDim[ 4 ];
3654   const double noneDblValue = 0.;
3655   const double noneIntValue = 0;
3656
3657   for ( size_t iF = 0; iF < fields.length(); ++iF )
3658   {
3659     // set field data
3660
3661     int dim = fields[ iF ]->GetDimension();
3662     SMDSAbs_ElementType elemType;
3663     TopAbs_ShapeEnum    shapeType;
3664     switch ( dim ) {
3665     case 0: elemType = SMDSAbs_0DElement; shapeType = TopAbs_VERTEX; break;
3666     case 1: elemType = SMDSAbs_Edge;      shapeType = TopAbs_EDGE;   break;
3667     case 2: elemType = SMDSAbs_Face;      shapeType = TopAbs_FACE;   break;
3668     case 3: elemType = SMDSAbs_Volume;    shapeType = TopAbs_SOLID;  break;
3669     default:
3670       continue; // skip fields on whole shape
3671     }
3672     GEOM::field_data_type dataType = fields[ iF ]->GetDataType();
3673     if ( dataType == GEOM::FDT_String )
3674       continue;
3675     GEOM::ListOfLong_var stepIDs = fields[ iF ]->GetSteps();
3676     if ( stepIDs->length() < 1 )
3677       continue;
3678     GEOM::string_array_var comps = fields[ iF ]->GetComponents();
3679     if ( comps->length() < 1 )
3680       continue;
3681     CORBA::String_var       name = fields[ iF ]->GetName();
3682
3683     if ( !fieldWriter.Set( meshDS,
3684                            name.in(),
3685                            elemType,
3686                            comps->length(),
3687                            /*isIntData=*/false ))//( dataType == GEOM::FDT_Int )))
3688       continue;
3689
3690     for ( size_t iC = 0; iC < comps->length(); ++iC )
3691       fieldWriter.SetCompName( iC, comps[ iC ].in() );
3692
3693     dblVals.resize( comps->length() );
3694     intVals.resize( comps->length() );
3695
3696     // find sub-shape IDs
3697
3698     std::vector< int >& subIds = subIdsByDim[ dim ];
3699     if ( subIds.empty() )
3700       for ( int id = 1; id <= meshDS->MaxShapeIndex(); ++id )
3701         if ( meshDS->IndexToShape( id ).ShapeType() == shapeType )
3702           subIds.push_back( id );
3703
3704     // write steps
3705
3706     SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
3707     if ( !elemIt )
3708       continue;
3709
3710     for ( size_t iS = 0; iS < stepIDs->length(); ++iS )
3711     {
3712       GEOM::GEOM_FieldStep_var step = fields[ iF ]->GetStep( stepIDs[ iS ]);
3713       if ( step->_is_nil() )
3714         continue;
3715
3716       CORBA::Long stamp = step->GetStamp();
3717       CORBA::Long id    = step->GetID();
3718       fieldWriter.SetDtIt( int( stamp ), int( id ));
3719
3720       // fill dblVals or intVals
3721       for ( size_t iC = 0; iC < comps->length(); ++iC )
3722         if ( dataType == GEOM::FDT_Double )
3723         {
3724           dblVals[ iC ].clear();
3725           dblVals[ iC ].resize( meshDS->MaxShapeIndex()+1, 0 );
3726         }
3727         else
3728         {
3729           intVals[ iC ].clear();
3730           intVals[ iC ].resize( meshDS->MaxShapeIndex()+1, 0 );
3731         }
3732       switch ( dataType )
3733       {
3734       case GEOM::FDT_Double:
3735       {
3736         GEOM::GEOM_DoubleFieldStep_var dblStep = GEOM::GEOM_DoubleFieldStep::_narrow( step );
3737         if ( dblStep->_is_nil() ) continue;
3738         GEOM::ListOfDouble_var vv = dblStep->GetValues();
3739         if ( vv->length() != subIds.size() * comps->length() )
3740           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
3741         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
3742           for ( size_t iC = 0; iC < comps->length(); ++iC )
3743             dblVals[ iC ][ subIds[ iS ]] = vv[ iV++ ];
3744         break;
3745       }
3746       case GEOM::FDT_Int:
3747       {
3748         GEOM::GEOM_IntFieldStep_var intStep = GEOM::GEOM_IntFieldStep::_narrow( step );
3749         if ( intStep->_is_nil() ) continue;
3750         GEOM::ListOfLong_var vv = intStep->GetValues();
3751         if ( vv->length() != subIds.size() * comps->length() )
3752           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
3753         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
3754           for ( size_t iC = 0; iC < comps->length(); ++iC )
3755             intVals[ iC ][ subIds[ iS ]] = (int) vv[ iV++ ];
3756         break;
3757       }
3758       case GEOM::FDT_Bool:
3759       {
3760         GEOM::GEOM_BoolFieldStep_var boolStep = GEOM::GEOM_BoolFieldStep::_narrow( step );
3761         if ( boolStep->_is_nil() ) continue;
3762         GEOM::short_array_var vv = boolStep->GetValues();
3763         if ( vv->length() != subIds.size() * comps->length() )
3764           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
3765         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
3766           for ( size_t iC = 0; iC < comps->length(); ++iC )
3767             intVals[ iC ][ subIds[ iS ]] = (int) vv[ iV++ ];
3768         break;
3769       }
3770       default: continue;
3771       }
3772
3773       // pass values to fieldWriter
3774       elemIt = fieldWriter.GetOrderedElems();
3775       if ( dataType == GEOM::FDT_Double )
3776         while ( elemIt->more() )
3777         {
3778           const SMDS_MeshElement* e = elemIt->next();
3779           const int shapeID = e->getshapeId();
3780           if ( shapeID < 1 || shapeID >= (int) dblVals[0].size() )
3781             for ( size_t iC = 0; iC < comps->length(); ++iC )
3782               fieldWriter.AddValue( noneDblValue );
3783           else
3784             for ( size_t iC = 0; iC < comps->length(); ++iC )
3785               fieldWriter.AddValue( dblVals[ iC ][ shapeID ]);
3786         }
3787       else
3788         while ( elemIt->more() )
3789         {
3790           const SMDS_MeshElement* e = elemIt->next();
3791           const int shapeID = e->getshapeId();
3792           if ( shapeID < 1 || shapeID >= (int) intVals[0].size() )
3793             for ( size_t iC = 0; iC < comps->length(); ++iC )
3794               fieldWriter.AddValue( (double) noneIntValue );
3795           else
3796             for ( size_t iC = 0; iC < comps->length(); ++iC )
3797               fieldWriter.AddValue( (double) intVals[ iC ][ shapeID ]);
3798         }
3799
3800       // write a step
3801       fieldWriter.Perform();
3802       SMESH_ComputeErrorPtr res = fieldWriter.GetError();
3803       if ( res && res->IsKO() )
3804       {
3805         if ( res->myComment.empty() )
3806         { THROW_SALOME_CORBA_EXCEPTION( METH "Fatal error", SALOME::INTERNAL_ERROR ); }
3807         else
3808         { THROW_SALOME_CORBA_EXCEPTION( res->myComment.c_str(), SALOME::INTERNAL_ERROR ); }
3809       }
3810
3811     } // loop on steps
3812   } // loop on fields
3813
3814   if ( !geomAssocFields || !geomAssocFields[0] )
3815     return;
3816
3817   // write geomAssocFields
3818
3819   std::vector< int > shapeDim( TopAbs_SHAPE + 1 );
3820   shapeDim[ TopAbs_COMPOUND  ] = 3;
3821   shapeDim[ TopAbs_COMPSOLID ] = 3;
3822   shapeDim[ TopAbs_SOLID     ] = 3;
3823   shapeDim[ TopAbs_SHELL     ] = 2;
3824   shapeDim[ TopAbs_FACE      ] = 2;
3825   shapeDim[ TopAbs_WIRE      ] = 1;
3826   shapeDim[ TopAbs_EDGE      ] = 1;
3827   shapeDim[ TopAbs_VERTEX    ] = 0;
3828   shapeDim[ TopAbs_SHAPE     ] = 3;
3829
3830   for ( int iF = 0; geomAssocFields[ iF ]; ++iF )
3831   {
3832     std::vector< std::string > compNames;
3833     switch ( geomAssocFields[ iF ]) {
3834     case 'v': case 'V':
3835       fieldWriter.Set( meshDS, "_vertices_", SMDSAbs_Node, /*nbComps=*/2, /*isInt=*/false );
3836       compNames.push_back( "dim" );
3837       break;
3838     case 'e': case 'E':
3839       fieldWriter.Set( meshDS, "_edges_", SMDSAbs_Edge, /*nbComps=*/1, /*isInt=*/false );
3840       break;
3841     case 'f': case 'F':
3842       fieldWriter.Set( meshDS, "_faces_", SMDSAbs_Face, /*nbComps=*/1, /*isInt=*/false );
3843       break;
3844     case 's': case 'S':
3845       fieldWriter.Set( meshDS, "_solids_", SMDSAbs_Volume, /*nbComps=*/1, /*isInt=*/false );
3846       break;
3847     default: continue;
3848     }
3849     compNames.push_back( "id" );
3850     for ( size_t iC = 0; iC < compNames.size(); ++iC )
3851       fieldWriter.SetCompName( iC, compNames[ iC ].c_str() );
3852
3853     fieldWriter.SetDtIt( -1, -1 );
3854
3855     SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
3856     if ( !elemIt )
3857       continue;
3858
3859     if ( compNames.size() == 2 ) // _vertices_
3860       while ( elemIt->more() )
3861       {
3862         const SMDS_MeshElement* e = elemIt->next();
3863         const int shapeID = e->getshapeId();
3864         if ( shapeID < 1 )
3865         {
3866           fieldWriter.AddValue( (double) -1 );
3867           fieldWriter.AddValue( (double) -1 );
3868         }
3869         else
3870         {
3871           const TopoDS_Shape& S = meshDS->IndexToShape( shapeID );
3872           fieldWriter.AddValue( (double) ( S.IsNull() ? -1 : shapeDim[ S.ShapeType() ]));
3873           fieldWriter.AddValue( (double) shapeID );
3874         }
3875       }
3876     else
3877       while ( elemIt->more() )
3878       {
3879         const SMDS_MeshElement* e = elemIt->next();
3880         const int shapeID = e->getshapeId();
3881         if ( shapeID < 1 )
3882           fieldWriter.AddValue( (double) -1 );
3883         else
3884           fieldWriter.AddValue( (double) shapeID );
3885       }
3886
3887     // write a step
3888     fieldWriter.Perform();
3889     SMESH_ComputeErrorPtr res = fieldWriter.GetError();
3890     if ( res && res->IsKO() )
3891     {
3892       if ( res->myComment.empty() )
3893       { THROW_SALOME_CORBA_EXCEPTION( METH "Fatal error", SALOME::INTERNAL_ERROR ); }
3894       else
3895       { THROW_SALOME_CORBA_EXCEPTION( res->myComment.c_str(), SALOME::INTERNAL_ERROR ); }
3896     }
3897
3898   } // loop on geomAssocFields
3899
3900 #undef METH
3901 }
3902
3903 //================================================================================
3904 /*!
3905  * \brief Export a part of mesh to a DAT file
3906  */
3907 //================================================================================
3908
3909 void SMESH_Mesh_i::ExportPartToDAT(::SMESH::SMESH_IDSource_ptr meshPart,
3910                                    const char*                 file)
3911   throw (SALOME::SALOME_Exception)
3912 {
3913   Unexpect aCatch(SALOME_SalomeException);
3914   if ( _preMeshInfo )
3915     _preMeshInfo->FullLoadFromFile();
3916
3917   PrepareForWriting(file);
3918
3919   SMESH_MeshPartDS partDS( meshPart );
3920   _impl->ExportDAT(file,&partDS);
3921
3922   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
3923                 << ".ExportPartToDAT( " << meshPart << ", r'" << file << "' )";
3924 }
3925 //================================================================================
3926 /*!
3927  * \brief Export a part of mesh to an UNV file
3928  */
3929 //================================================================================
3930
3931 void SMESH_Mesh_i::ExportPartToUNV(::SMESH::SMESH_IDSource_ptr meshPart,
3932                                    const char*                 file)
3933   throw (SALOME::SALOME_Exception)
3934 {
3935   Unexpect aCatch(SALOME_SalomeException);
3936   if ( _preMeshInfo )
3937     _preMeshInfo->FullLoadFromFile();
3938
3939   PrepareForWriting(file);
3940
3941   SMESH_MeshPartDS partDS( meshPart );
3942   _impl->ExportUNV(file, &partDS);
3943
3944   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
3945                 << ".ExportPartToUNV( " << meshPart<< ", r'" << file << "' )";
3946 }
3947 //================================================================================
3948 /*!
3949  * \brief Export a part of mesh to an STL file
3950  */
3951 //================================================================================
3952
3953 void SMESH_Mesh_i::ExportPartToSTL(::SMESH::SMESH_IDSource_ptr meshPart,
3954                                    const char*                 file,
3955                                    ::CORBA::Boolean            isascii)
3956   throw (SALOME::SALOME_Exception)
3957 {
3958   Unexpect aCatch(SALOME_SalomeException);
3959   if ( _preMeshInfo )
3960     _preMeshInfo->FullLoadFromFile();
3961
3962   PrepareForWriting(file);
3963
3964   CORBA::String_var name;
3965   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( meshPart );
3966   if ( !so->_is_nil() )
3967     name = so->GetName();
3968
3969   SMESH_MeshPartDS partDS( meshPart );
3970   _impl->ExportSTL( file, isascii, name.in(), &partDS );
3971
3972   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportPartToSTL( "
3973                 << meshPart<< ", r'" << file << "', " << isascii << ")";
3974 }
3975
3976 //================================================================================
3977 /*!
3978  * \brief Export a part of mesh to an STL file
3979  */
3980 //================================================================================
3981
3982 void SMESH_Mesh_i::ExportCGNS(::SMESH::SMESH_IDSource_ptr meshPart,
3983                               const char*                 file,
3984                               CORBA::Boolean              overwrite,
3985                               CORBA::Boolean              groupElemsByType)
3986   throw (SALOME::SALOME_Exception)
3987 {
3988 #ifdef WITH_CGNS
3989   Unexpect aCatch(SALOME_SalomeException);
3990   if ( _preMeshInfo )
3991     _preMeshInfo->FullLoadFromFile();
3992
3993   PrepareForWriting(file,overwrite);
3994
3995   std::string meshName("");
3996   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( meshPart );
3997   if ( !so->_is_nil() )
3998   {
3999     CORBA::String_var name = so->GetName();
4000     meshName = name.in();
4001   }
4002   SMESH_TRY;
4003
4004   SMESH_MeshPartDS partDS( meshPart );
4005   _impl->ExportCGNS(file, &partDS, meshName.c_str(), groupElemsByType );
4006
4007   SMESH_CATCH( SMESH::throwCorbaException );
4008
4009   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportCGNS( "
4010                 << meshPart<< ", r'" << file << "', " << overwrite << ")";
4011 #else
4012   THROW_SALOME_CORBA_EXCEPTION("CGNS library is unavailable", SALOME::INTERNAL_ERROR);
4013 #endif
4014 }
4015
4016 //================================================================================
4017 /*!
4018  * \brief Export a part of mesh to a GMF file
4019  */
4020 //================================================================================
4021
4022 void SMESH_Mesh_i::ExportGMF(::SMESH::SMESH_IDSource_ptr meshPart,
4023                              const char*                 file,
4024                              bool                        withRequiredGroups)
4025   throw (SALOME::SALOME_Exception)
4026 {
4027   Unexpect aCatch(SALOME_SalomeException);
4028   if ( _preMeshInfo )
4029     _preMeshInfo->FullLoadFromFile();
4030
4031   PrepareForWriting(file,/*overwrite=*/true);
4032
4033   SMESH_MeshPartDS partDS( meshPart );
4034   _impl->ExportGMF(file, &partDS, withRequiredGroups);
4035
4036   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportGMF( "
4037                 << meshPart<< ", r'"
4038                 << file << "', "
4039                 << withRequiredGroups << ")";
4040 }
4041
4042 //=============================================================================
4043 /*!
4044  * Return computation progress [0.,1]
4045  */
4046 //=============================================================================
4047
4048 CORBA::Double SMESH_Mesh_i::GetComputeProgress()
4049 {
4050   SMESH_TRY;
4051
4052   return _impl->GetComputeProgress();
4053
4054   SMESH_CATCH( SMESH::doNothing );
4055   return 0.;
4056 }
4057
4058 CORBA::Long SMESH_Mesh_i::NbNodes()throw(SALOME::SALOME_Exception)
4059 {
4060   Unexpect aCatch(SALOME_SalomeException);
4061   if ( _preMeshInfo )
4062     return _preMeshInfo->NbNodes();
4063
4064   return _impl->NbNodes();
4065 }
4066
4067 CORBA::Long SMESH_Mesh_i::NbElements()throw (SALOME::SALOME_Exception)
4068 {
4069   Unexpect aCatch(SALOME_SalomeException);
4070   if ( _preMeshInfo )
4071     return _preMeshInfo->NbElements();
4072
4073   return Nb0DElements() + NbEdges() + NbFaces() + NbVolumes() + NbBalls();
4074 }
4075
4076 CORBA::Long SMESH_Mesh_i::Nb0DElements()throw (SALOME::SALOME_Exception)
4077 {
4078   Unexpect aCatch(SALOME_SalomeException);
4079   if ( _preMeshInfo )
4080     return _preMeshInfo->Nb0DElements();
4081
4082   return _impl->Nb0DElements();
4083 }
4084
4085 CORBA::Long SMESH_Mesh_i::NbBalls() throw (SALOME::SALOME_Exception)
4086 {
4087   Unexpect aCatch(SALOME_SalomeException);
4088   if ( _preMeshInfo )
4089     return _preMeshInfo->NbBalls();
4090
4091   return _impl->NbBalls();
4092 }
4093
4094 CORBA::Long SMESH_Mesh_i::NbEdges()throw(SALOME::SALOME_Exception)
4095 {
4096   Unexpect aCatch(SALOME_SalomeException);
4097   if ( _preMeshInfo )
4098     return _preMeshInfo->NbEdges();
4099
4100   return _impl->NbEdges();
4101 }
4102
4103 CORBA::Long SMESH_Mesh_i::NbEdgesOfOrder(SMESH::ElementOrder order)
4104   throw(SALOME::SALOME_Exception)
4105 {
4106   Unexpect aCatch(SALOME_SalomeException);
4107   if ( _preMeshInfo )
4108     return _preMeshInfo->NbEdges( (SMDSAbs_ElementOrder) order );
4109
4110   return _impl->NbEdges( (SMDSAbs_ElementOrder) order);
4111 }
4112
4113 //=============================================================================
4114
4115 CORBA::Long SMESH_Mesh_i::NbFaces()throw(SALOME::SALOME_Exception)
4116 {
4117   Unexpect aCatch(SALOME_SalomeException);
4118   if ( _preMeshInfo )
4119     return _preMeshInfo->NbFaces();
4120
4121   return _impl->NbFaces();
4122 }
4123
4124 CORBA::Long SMESH_Mesh_i::NbTriangles()throw(SALOME::SALOME_Exception)
4125 {
4126   Unexpect aCatch(SALOME_SalomeException);
4127   if ( _preMeshInfo )
4128     return _preMeshInfo->NbTriangles();
4129
4130   return _impl->NbTriangles();
4131 }
4132
4133 CORBA::Long SMESH_Mesh_i::NbBiQuadTriangles()throw(SALOME::SALOME_Exception)
4134 {
4135   Unexpect aCatch(SALOME_SalomeException);
4136   if ( _preMeshInfo )
4137     return _preMeshInfo->NbBiQuadTriangles();
4138
4139   return _impl->NbBiQuadTriangles();
4140 }
4141
4142 CORBA::Long SMESH_Mesh_i::NbQuadrangles()throw(SALOME::SALOME_Exception)
4143 {
4144   Unexpect aCatch(SALOME_SalomeException);
4145   if ( _preMeshInfo )
4146     return _preMeshInfo->NbQuadrangles();
4147
4148   return _impl->NbQuadrangles();
4149 }
4150
4151 CORBA::Long SMESH_Mesh_i::NbBiQuadQuadrangles()throw(SALOME::SALOME_Exception)
4152 {
4153   Unexpect aCatch(SALOME_SalomeException);
4154   if ( _preMeshInfo )
4155     return _preMeshInfo->NbBiQuadQuadrangles();
4156
4157   return _impl->NbBiQuadQuadrangles();
4158 }
4159
4160 CORBA::Long SMESH_Mesh_i::NbPolygons() throw(SALOME::SALOME_Exception)
4161 {
4162   Unexpect aCatch(SALOME_SalomeException);
4163   if ( _preMeshInfo )
4164     return _preMeshInfo->NbPolygons();
4165
4166   return _impl->NbPolygons();
4167 }
4168
4169 CORBA::Long SMESH_Mesh_i::NbPolygonsOfOrder(SMESH::ElementOrder order) throw(SALOME::SALOME_Exception)
4170 {
4171   Unexpect aCatch(SALOME_SalomeException);
4172   if ( _preMeshInfo )
4173     return _preMeshInfo->NbPolygons((SMDSAbs_ElementOrder) order);
4174
4175   return _impl->NbPolygons((SMDSAbs_ElementOrder)order);
4176 }
4177
4178 CORBA::Long SMESH_Mesh_i::NbFacesOfOrder(SMESH::ElementOrder order)
4179   throw(SALOME::SALOME_Exception)
4180 {
4181   Unexpect aCatch(SALOME_SalomeException);
4182   if ( _preMeshInfo )
4183     return _preMeshInfo->NbFaces( (SMDSAbs_ElementOrder) order );
4184
4185   return _impl->NbFaces( (SMDSAbs_ElementOrder) order);
4186 }
4187
4188 CORBA::Long SMESH_Mesh_i::NbTrianglesOfOrder(SMESH::ElementOrder order)
4189   throw(SALOME::SALOME_Exception)
4190 {
4191   Unexpect aCatch(SALOME_SalomeException);
4192   if ( _preMeshInfo )
4193     return _preMeshInfo->NbTriangles( (SMDSAbs_ElementOrder) order );
4194
4195   return _impl->NbTriangles( (SMDSAbs_ElementOrder) order);
4196 }
4197
4198 CORBA::Long SMESH_Mesh_i::NbQuadranglesOfOrder(SMESH::ElementOrder order)
4199   throw(SALOME::SALOME_Exception)
4200 {
4201   Unexpect aCatch(SALOME_SalomeException);
4202   if ( _preMeshInfo )
4203     return _preMeshInfo->NbQuadrangles( (SMDSAbs_ElementOrder) order );
4204
4205   return _impl->NbQuadrangles( (SMDSAbs_ElementOrder) order);
4206 }
4207
4208 //=============================================================================
4209
4210 CORBA::Long SMESH_Mesh_i::NbVolumes()throw(SALOME::SALOME_Exception)
4211 {
4212   Unexpect aCatch(SALOME_SalomeException);
4213   if ( _preMeshInfo )
4214     return _preMeshInfo->NbVolumes();
4215
4216   return _impl->NbVolumes();
4217 }
4218
4219 CORBA::Long SMESH_Mesh_i::NbTetras()throw(SALOME::SALOME_Exception)
4220 {
4221   Unexpect aCatch(SALOME_SalomeException);
4222   if ( _preMeshInfo )
4223     return _preMeshInfo->NbTetras();
4224
4225   return _impl->NbTetras();
4226 }
4227
4228 CORBA::Long SMESH_Mesh_i::NbHexas()throw(SALOME::SALOME_Exception)
4229 {
4230   Unexpect aCatch(SALOME_SalomeException);
4231   if ( _preMeshInfo )
4232     return _preMeshInfo->NbHexas();
4233
4234   return _impl->NbHexas();
4235 }
4236
4237 CORBA::Long SMESH_Mesh_i::NbTriQuadraticHexas()throw(SALOME::SALOME_Exception)
4238 {
4239   Unexpect aCatch(SALOME_SalomeException);
4240   if ( _preMeshInfo )
4241     return _preMeshInfo->NbTriQuadHexas();
4242
4243   return _impl->NbTriQuadraticHexas();
4244 }
4245
4246 CORBA::Long SMESH_Mesh_i::NbPyramids()throw(SALOME::SALOME_Exception)
4247 {
4248   Unexpect aCatch(SALOME_SalomeException);
4249   if ( _preMeshInfo )
4250     return _preMeshInfo->NbPyramids();
4251
4252   return _impl->NbPyramids();
4253 }
4254
4255 CORBA::Long SMESH_Mesh_i::NbPrisms()throw(SALOME::SALOME_Exception)
4256 {
4257   Unexpect aCatch(SALOME_SalomeException);
4258   if ( _preMeshInfo )
4259     return _preMeshInfo->NbPrisms();
4260
4261   return _impl->NbPrisms();
4262 }
4263
4264 CORBA::Long SMESH_Mesh_i::NbHexagonalPrisms()throw(SALOME::SALOME_Exception)
4265 {
4266   Unexpect aCatch(SALOME_SalomeException);
4267   if ( _preMeshInfo )
4268     return _preMeshInfo->NbHexPrisms();
4269
4270   return _impl->NbHexagonalPrisms();
4271 }
4272
4273 CORBA::Long SMESH_Mesh_i::NbPolyhedrons()throw(SALOME::SALOME_Exception)
4274 {
4275   Unexpect aCatch(SALOME_SalomeException);
4276   if ( _preMeshInfo )
4277     return _preMeshInfo->NbPolyhedrons();
4278
4279   return _impl->NbPolyhedrons();
4280 }
4281
4282 CORBA::Long SMESH_Mesh_i::NbVolumesOfOrder(SMESH::ElementOrder order)
4283   throw(SALOME::SALOME_Exception)
4284 {
4285   Unexpect aCatch(SALOME_SalomeException);
4286   if ( _preMeshInfo )
4287     return _preMeshInfo->NbVolumes( (SMDSAbs_ElementOrder) order );
4288
4289   return _impl->NbVolumes( (SMDSAbs_ElementOrder) order);
4290 }
4291
4292 CORBA::Long SMESH_Mesh_i::NbTetrasOfOrder(SMESH::ElementOrder order)
4293   throw(SALOME::SALOME_Exception)
4294 {
4295   Unexpect aCatch(SALOME_SalomeException);
4296   if ( _preMeshInfo )
4297     return _preMeshInfo->NbTetras( (SMDSAbs_ElementOrder) order);
4298
4299   return _impl->NbTetras( (SMDSAbs_ElementOrder) order);
4300 }
4301
4302 CORBA::Long SMESH_Mesh_i::NbHexasOfOrder(SMESH::ElementOrder order)
4303   throw(SALOME::SALOME_Exception)
4304 {
4305   Unexpect aCatch(SALOME_SalomeException);
4306   if ( _preMeshInfo )
4307     return _preMeshInfo->NbHexas( (SMDSAbs_ElementOrder) order);
4308
4309   return _impl->NbHexas( (SMDSAbs_ElementOrder) order);
4310 }
4311
4312 CORBA::Long SMESH_Mesh_i::NbPyramidsOfOrder(SMESH::ElementOrder order)
4313   throw(SALOME::SALOME_Exception)
4314 {
4315   Unexpect aCatch(SALOME_SalomeException);
4316   if ( _preMeshInfo )
4317     return _preMeshInfo->NbPyramids( (SMDSAbs_ElementOrder) order);
4318
4319   return _impl->NbPyramids( (SMDSAbs_ElementOrder) order);
4320 }
4321
4322 CORBA::Long SMESH_Mesh_i::NbPrismsOfOrder(SMESH::ElementOrder order)
4323   throw(SALOME::SALOME_Exception)
4324 {
4325   Unexpect aCatch(SALOME_SalomeException);
4326   if ( _preMeshInfo )
4327     return _preMeshInfo->NbPrisms( (SMDSAbs_ElementOrder) order);
4328
4329   return _impl->NbPrisms( (SMDSAbs_ElementOrder) order);
4330 }
4331
4332 //=============================================================================
4333 /*!
4334  * Returns nb of published sub-meshes
4335  */
4336 //=============================================================================
4337
4338 CORBA::Long SMESH_Mesh_i::NbSubMesh()throw(SALOME::SALOME_Exception)
4339 {
4340   Unexpect aCatch(SALOME_SalomeException);
4341   return _mapSubMesh_i.size();
4342 }
4343
4344 //=============================================================================
4345 /*!
4346  * Dumps mesh into a string
4347  */
4348 //=============================================================================
4349
4350 char* SMESH_Mesh_i::Dump()
4351 {
4352   ostringstream os;
4353   _impl->Dump( os );
4354   return CORBA::string_dup( os.str().c_str() );
4355 }
4356
4357 //=============================================================================
4358 /*!
4359  * Method of SMESH_IDSource interface
4360  */
4361 //=============================================================================
4362
4363 SMESH::long_array* SMESH_Mesh_i::GetIDs()
4364 {
4365   return GetElementsId();
4366 }
4367
4368 //=============================================================================
4369 /*!
4370  * Returns ids of all elements
4371  */
4372 //=============================================================================
4373
4374 SMESH::long_array* SMESH_Mesh_i::GetElementsId()
4375   throw (SALOME::SALOME_Exception)
4376 {
4377   Unexpect aCatch(SALOME_SalomeException);
4378   if ( _preMeshInfo )
4379     _preMeshInfo->FullLoadFromFile();
4380
4381   SMESH::long_array_var aResult = new SMESH::long_array();
4382   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
4383
4384   if ( aSMESHDS_Mesh == NULL )
4385     return aResult._retn();
4386
4387   long nbElements = NbElements();
4388   aResult->length( nbElements );
4389   SMDS_ElemIteratorPtr anIt = aSMESHDS_Mesh->elementsIterator();
4390   for ( int i = 0, n = nbElements; i < n && anIt->more(); i++ )
4391     aResult[i] = anIt->next()->GetID();
4392
4393   return aResult._retn();
4394 }
4395
4396
4397 //=============================================================================
4398 /*!
4399  * Returns ids of all elements of given type
4400  */
4401 //=============================================================================
4402
4403 SMESH::long_array* SMESH_Mesh_i::GetElementsByType( SMESH::ElementType theElemType )
4404     throw (SALOME::SALOME_Exception)
4405 {
4406   Unexpect aCatch(SALOME_SalomeException);
4407   if ( _preMeshInfo )
4408     _preMeshInfo->FullLoadFromFile();
4409
4410   SMESH::long_array_var aResult = new SMESH::long_array();
4411   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
4412
4413   if ( aSMESHDS_Mesh == NULL )
4414     return aResult._retn();
4415
4416   long nbElements = NbElements();
4417
4418   // No sense in returning ids of elements along with ids of nodes:
4419   // when theElemType == SMESH::ALL, return node ids only if
4420   // there are no elements
4421   if ( theElemType == SMESH::NODE || (theElemType == SMESH::ALL && nbElements == 0) )
4422     return GetNodesId();
4423
4424   aResult->length( nbElements );
4425
4426   int i = 0;
4427
4428   SMDS_ElemIteratorPtr anIt = aSMESHDS_Mesh->elementsIterator( (SMDSAbs_ElementType)theElemType );
4429   while ( i < nbElements && anIt->more() )
4430     aResult[i++] = anIt->next()->GetID();
4431
4432   aResult->length( i );
4433
4434   return aResult._retn();
4435 }
4436
4437 //=============================================================================
4438 /*!
4439  * Returns ids of all nodes
4440  */
4441 //=============================================================================
4442
4443 SMESH::long_array* SMESH_Mesh_i::GetNodesId()
4444   throw (SALOME::SALOME_Exception)
4445 {
4446   Unexpect aCatch(SALOME_SalomeException);
4447   if ( _preMeshInfo )
4448     _preMeshInfo->FullLoadFromFile();
4449
4450   SMESH::long_array_var aResult = new SMESH::long_array();
4451   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4452
4453   if ( aMeshDS == NULL )
4454     return aResult._retn();
4455
4456   long nbNodes = NbNodes();
4457   aResult->length( nbNodes );
4458   SMDS_NodeIteratorPtr anIt = aMeshDS->nodesIterator();
4459   for ( int i = 0, n = nbNodes; i < n && anIt->more(); i++ )
4460     aResult[i] = anIt->next()->GetID();
4461
4462   return aResult._retn();
4463 }
4464
4465 //=============================================================================
4466 /*!
4467  *
4468  */
4469 //=============================================================================
4470
4471 SMESH::ElementType SMESH_Mesh_i::GetElementType( const CORBA::Long id, const bool iselem )
4472   throw (SALOME::SALOME_Exception)
4473 {
4474   SMESH::ElementType type = SMESH::ALL;
4475   SMESH_TRY;
4476
4477   if ( _preMeshInfo )
4478     _preMeshInfo->FullLoadFromFile();
4479
4480   type = ( SMESH::ElementType ) _impl->GetElementType( id, iselem );
4481
4482   SMESH_CATCH( SMESH::throwCorbaException );
4483
4484   return type;
4485 }
4486
4487 //=============================================================================
4488 /*!
4489  *
4490  */
4491 //=============================================================================
4492
4493 SMESH::EntityType SMESH_Mesh_i::GetElementGeomType( const CORBA::Long id )
4494   throw (SALOME::SALOME_Exception)
4495 {
4496   if ( _preMeshInfo )
4497     _preMeshInfo->FullLoadFromFile();
4498
4499   const SMDS_MeshElement* e = _impl->GetMeshDS()->FindElement(id);
4500   if ( !e )
4501     THROW_SALOME_CORBA_EXCEPTION( "invalid element id", SALOME::BAD_PARAM );
4502
4503   return ( SMESH::EntityType ) e->GetEntityType();
4504 }
4505
4506 //=============================================================================
4507 /*!
4508  *
4509  */
4510 //=============================================================================
4511
4512 SMESH::GeometryType SMESH_Mesh_i::GetElementShape( const CORBA::Long id )
4513   throw (SALOME::SALOME_Exception)
4514 {
4515   if ( _preMeshInfo )
4516     _preMeshInfo->FullLoadFromFile();
4517
4518   const SMDS_MeshElement* e = _impl->GetMeshDS()->FindElement(id);
4519   if ( !e )
4520     THROW_SALOME_CORBA_EXCEPTION( "invalid element id", SALOME::BAD_PARAM );
4521
4522   return ( SMESH::GeometryType ) e->GetGeomType();
4523 }
4524
4525 //=============================================================================
4526 /*!
4527  * Returns ID of elements for given submesh
4528  */
4529 //=============================================================================
4530 SMESH::long_array* SMESH_Mesh_i::GetSubMeshElementsId(const CORBA::Long ShapeID)
4531      throw (SALOME::SALOME_Exception)
4532 {
4533   SMESH::long_array_var aResult = new SMESH::long_array();
4534
4535   SMESH_TRY;
4536   if ( _preMeshInfo )
4537     _preMeshInfo->FullLoadFromFile();
4538
4539   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
4540   if(!SM) return aResult._retn();
4541
4542   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
4543   if(!SDSM) return aResult._retn();
4544
4545   aResult->length(SDSM->NbElements());
4546
4547   SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
4548   int i = 0;
4549   while ( eIt->more() ) {
4550     aResult[i++] = eIt->next()->GetID();
4551   }
4552
4553   SMESH_CATCH( SMESH::throwCorbaException );
4554
4555   return aResult._retn();
4556 }
4557
4558 //=============================================================================
4559 /*!
4560  * Returns ID of nodes for given submesh
4561  * If param all==true - returns all nodes, else -
4562  * returns only nodes on shapes.
4563  */
4564 //=============================================================================
4565
4566 SMESH::long_array* SMESH_Mesh_i::GetSubMeshNodesId(const CORBA::Long ShapeID,
4567                                                    CORBA::Boolean    all)
4568   throw (SALOME::SALOME_Exception)
4569 {
4570   SMESH::long_array_var aResult = new SMESH::long_array();
4571
4572   SMESH_TRY;
4573   if ( _preMeshInfo )
4574     _preMeshInfo->FullLoadFromFile();
4575
4576   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
4577   if(!SM) return aResult._retn();
4578
4579   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
4580   if(!SDSM) return aResult._retn();
4581
4582   set<int> theElems;
4583   if( !all || (SDSM->NbElements()==0) ) { // internal nodes or vertex submesh
4584     SMDS_NodeIteratorPtr nIt = SDSM->GetNodes();
4585     while ( nIt->more() ) {
4586       const SMDS_MeshNode* elem = nIt->next();
4587       theElems.insert( elem->GetID() );
4588     }
4589   }
4590   else { // all nodes of submesh elements
4591     SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
4592     while ( eIt->more() ) {
4593       const SMDS_MeshElement* anElem = eIt->next();
4594       SMDS_ElemIteratorPtr nIt = anElem->nodesIterator();
4595       while ( nIt->more() ) {
4596         const SMDS_MeshElement* elem = nIt->next();
4597         theElems.insert( elem->GetID() );
4598       }
4599     }
4600   }
4601
4602   aResult->length(theElems.size());
4603   set<int>::iterator itElem;
4604   int i = 0;
4605   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4606     aResult[i++] = *itElem;
4607
4608   SMESH_CATCH( SMESH::throwCorbaException );
4609
4610   return aResult._retn();
4611 }
4612
4613 //=============================================================================
4614 /*!
4615  * Returns type of elements for given submesh
4616  */
4617 //=============================================================================
4618
4619 SMESH::ElementType SMESH_Mesh_i::GetSubMeshElementType(const CORBA::Long ShapeID)
4620   throw (SALOME::SALOME_Exception)
4621 {
4622   SMESH::ElementType type = SMESH::ALL;
4623
4624   SMESH_TRY;
4625   if ( _preMeshInfo )
4626     _preMeshInfo->FullLoadFromFile();
4627
4628   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
4629   if(!SM) return SMESH::ALL;
4630
4631   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
4632   if(!SDSM) return SMESH::ALL;
4633
4634   if(SDSM->NbElements()==0)
4635     return (SM->GetSubShape().ShapeType() == TopAbs_VERTEX) ? SMESH::NODE : SMESH::ALL;
4636
4637   SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
4638   const SMDS_MeshElement* anElem = eIt->next();
4639
4640   type = ( SMESH::ElementType ) anElem->GetType();
4641
4642   SMESH_CATCH( SMESH::throwCorbaException );
4643
4644   return type;
4645 }
4646
4647
4648 //=============================================================================
4649 /*!
4650  * Returns pointer to _impl as an integer value. Is called from constructor of SMESH_Client
4651  */
4652 //=============================================================================
4653
4654 CORBA::LongLong SMESH_Mesh_i::GetMeshPtr()
4655 {
4656   if ( _preMeshInfo )
4657     _preMeshInfo->FullLoadFromFile();
4658
4659   CORBA::LongLong pointeur = CORBA::LongLong(_impl);
4660   if ( MYDEBUG ) MESSAGE("CORBA::LongLong SMESH_Mesh_i::GetMeshPtr() "<<pointeur);
4661   return pointeur;
4662 }
4663
4664
4665 //=============================================================================
4666 /*!
4667  * Get XYZ coordinates of node as list of double
4668  * If there is not node for given ID - returns empty list
4669  */
4670 //=============================================================================
4671
4672 SMESH::double_array* SMESH_Mesh_i::GetNodeXYZ(const CORBA::Long id)
4673 {
4674   if ( _preMeshInfo )
4675     _preMeshInfo->FullLoadFromFile();
4676
4677   SMESH::double_array_var aResult = new SMESH::double_array();
4678   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4679   if ( aMeshDS == NULL )
4680     return aResult._retn();
4681
4682   // find node
4683   const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
4684   if(!aNode)
4685     return aResult._retn();
4686
4687   // add coordinates
4688   aResult->length(3);
4689   aResult[0] = aNode->X();
4690   aResult[1] = aNode->Y();
4691   aResult[2] = aNode->Z();
4692   return aResult._retn();
4693 }
4694
4695
4696 //=============================================================================
4697 /*!
4698  * For given node returns list of IDs of inverse elements
4699  * If there is not node for given ID - returns empty list
4700  */
4701 //=============================================================================
4702
4703 SMESH::long_array* SMESH_Mesh_i::GetNodeInverseElements(const CORBA::Long  id,
4704                                                         SMESH::ElementType elemType)
4705 {
4706   if ( _preMeshInfo )
4707     _preMeshInfo->FullLoadFromFile();
4708
4709   SMESH::long_array_var aResult = new SMESH::long_array();
4710   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4711   if ( aMeshDS == NULL )
4712     return aResult._retn();
4713
4714   // find node
4715   const SMDS_MeshNode* aNode = aMeshDS->FindNode( id );
4716   if ( !aNode )
4717     return aResult._retn();
4718
4719   // find inverse elements
4720   SMDSAbs_ElementType type = SMDSAbs_ElementType( elemType );
4721   SMDS_ElemIteratorPtr eIt = aNode->GetInverseElementIterator( type );
4722   aResult->length( aNode->NbInverseElements( type ));
4723   for( int i = 0; eIt->more(); ++i )
4724   {
4725     const SMDS_MeshElement* elem = eIt->next();
4726     aResult[ i ] = elem->GetID();
4727   }
4728   return aResult._retn();
4729 }
4730
4731 //=============================================================================
4732 /*!
4733  * \brief Return position of a node on shape
4734  */
4735 //=============================================================================
4736
4737 SMESH::NodePosition* SMESH_Mesh_i::GetNodePosition(CORBA::Long NodeID)
4738 {
4739   if ( _preMeshInfo )
4740     _preMeshInfo->FullLoadFromFile();
4741
4742   SMESH::NodePosition* aNodePosition = new SMESH::NodePosition();
4743   aNodePosition->shapeID = 0;
4744   aNodePosition->shapeType = GEOM::SHAPE;
4745
4746   SMESHDS_Mesh* mesh = _impl->GetMeshDS();
4747   if ( !mesh ) return aNodePosition;
4748
4749   if ( const SMDS_MeshNode* aNode = mesh->FindNode(NodeID) )
4750   {
4751     if ( SMDS_PositionPtr pos = aNode->GetPosition() )
4752     {
4753       aNodePosition->shapeID = aNode->getshapeId();
4754       switch ( pos->GetTypeOfPosition() ) {
4755       case SMDS_TOP_EDGE:
4756         aNodePosition->shapeType = GEOM::EDGE;
4757         aNodePosition->params.length(1);
4758         aNodePosition->params[0] = SMDS_EdgePositionPtr( pos )->GetUParameter();
4759         break;
4760       case SMDS_TOP_FACE: {
4761         SMDS_FacePositionPtr fPos = pos;
4762         aNodePosition->shapeType = GEOM::FACE;
4763         aNodePosition->params.length(2);
4764         aNodePosition->params[0] = fPos->GetUParameter();
4765         aNodePosition->params[1] = fPos->GetVParameter();
4766         break;
4767       }
4768       case SMDS_TOP_VERTEX:
4769         aNodePosition->shapeType = GEOM::VERTEX;
4770         break;
4771       case SMDS_TOP_3DSPACE:
4772         if ( TopExp_Explorer(_impl->GetShapeToMesh(), TopAbs_SOLID).More() )
4773           aNodePosition->shapeType = GEOM::SOLID;
4774         else if ( TopExp_Explorer(_impl->GetShapeToMesh(), TopAbs_SHELL).More() )
4775           aNodePosition->shapeType = GEOM::SHELL;
4776         break;
4777       default:;
4778       }
4779     }
4780   }
4781   return aNodePosition;
4782 }
4783
4784 //=============================================================================
4785 /*!
4786  * \brief Return position of an element on shape
4787  */
4788 //=============================================================================
4789
4790 SMESH::ElementPosition SMESH_Mesh_i::GetElementPosition(CORBA::Long ElemID)
4791 {
4792   if ( _preMeshInfo )
4793     _preMeshInfo->FullLoadFromFile();
4794
4795   SMESH::ElementPosition anElementPosition;
4796   anElementPosition.shapeID = 0;
4797   anElementPosition.shapeType = GEOM::SHAPE;
4798
4799   SMESHDS_Mesh* mesh = _impl->GetMeshDS();
4800   if ( !mesh ) return anElementPosition;
4801
4802   if ( const SMDS_MeshElement* anElem = mesh->FindElement( ElemID ) )
4803   {
4804     anElementPosition.shapeID = anElem->getshapeId();
4805     const TopoDS_Shape& aSp = mesh->IndexToShape( anElem->getshapeId() );
4806     if ( !aSp.IsNull() ) {
4807       switch ( aSp.ShapeType() ) {
4808       case TopAbs_EDGE:
4809         anElementPosition.shapeType = GEOM::EDGE;
4810         break;
4811       case TopAbs_FACE:
4812         anElementPosition.shapeType = GEOM::FACE;
4813         break;
4814       case TopAbs_VERTEX:
4815         anElementPosition.shapeType = GEOM::VERTEX;
4816         break;
4817       case TopAbs_SOLID:
4818         anElementPosition.shapeType = GEOM::SOLID;
4819         break;
4820       case TopAbs_SHELL:
4821         anElementPosition.shapeType = GEOM::SHELL;
4822         break;
4823       default:;
4824       }
4825     }
4826   }
4827   return anElementPosition;
4828 }
4829
4830 //=============================================================================
4831 /*!
4832  * If given element is node returns IDs of shape from position
4833  * If there is not node for given ID - returns -1
4834  */
4835 //=============================================================================
4836
4837 CORBA::Long SMESH_Mesh_i::GetShapeID(const CORBA::Long id)
4838 {
4839   if ( _preMeshInfo )
4840     _preMeshInfo->FullLoadFromFile();
4841
4842   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4843   if ( aMeshDS == NULL )
4844     return -1;
4845
4846   // try to find node
4847   const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
4848   if(aNode) {
4849     return aNode->getshapeId();
4850   }
4851
4852   return -1;
4853 }
4854
4855
4856 //=============================================================================
4857 /*!
4858  * For given element returns ID of result shape after
4859  * ::FindShape() from SMESH_MeshEditor
4860  * If there is not element for given ID - returns -1
4861  */
4862 //=============================================================================
4863
4864 CORBA::Long SMESH_Mesh_i::GetShapeIDForElem(const CORBA::Long id)
4865 {
4866   if ( _preMeshInfo )
4867     _preMeshInfo->FullLoadFromFile();
4868
4869   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4870   if ( aMeshDS == NULL )
4871     return -1;
4872
4873   // try to find element
4874   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
4875   if(!elem)
4876     return -1;
4877
4878   ::SMESH_MeshEditor aMeshEditor(_impl);
4879   int index = aMeshEditor.FindShape( elem );
4880   if(index>0)
4881     return index;
4882
4883   return -1;
4884 }
4885
4886
4887 //=============================================================================
4888 /*!
4889  * Returns number of nodes for given element
4890  * If there is not element for given ID - returns -1
4891  */
4892 //=============================================================================
4893
4894 CORBA::Long SMESH_Mesh_i::GetElemNbNodes(const CORBA::Long id)
4895 {
4896   if ( _preMeshInfo )
4897     _preMeshInfo->FullLoadFromFile();
4898
4899   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4900   if ( aMeshDS == NULL ) return -1;
4901   // try to find element
4902   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
4903   if(!elem) return -1;
4904   return elem->NbNodes();
4905 }
4906
4907
4908 //=============================================================================
4909 /*!
4910  * Returns ID of node by given index for given element
4911  * If there is not element for given ID - returns -1
4912  * If there is not node for given index - returns -2
4913  */
4914 //=============================================================================
4915
4916 CORBA::Long SMESH_Mesh_i::GetElemNode(const CORBA::Long id, const CORBA::Long index)
4917 {
4918   if ( _preMeshInfo )
4919     _preMeshInfo->FullLoadFromFile();
4920
4921   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4922   if ( aMeshDS == NULL ) return -1;
4923   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
4924   if(!elem) return -1;
4925   if( index>=elem->NbNodes() || index<0 ) return -1;
4926   return elem->GetNode(index)->GetID();
4927 }
4928
4929 //=============================================================================
4930 /*!
4931  * Returns IDs of nodes of given element
4932  */
4933 //=============================================================================
4934
4935 SMESH::long_array* SMESH_Mesh_i::GetElemNodes(const CORBA::Long id)
4936 {
4937   if ( _preMeshInfo )
4938     _preMeshInfo->FullLoadFromFile();
4939
4940   SMESH::long_array_var aResult = new SMESH::long_array();
4941   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() )
4942   {
4943     if ( const SMDS_MeshElement* elem = aMeshDS->FindElement(id) )
4944     {
4945       aResult->length( elem->NbNodes() );
4946       for ( CORBA::ULong i = 0; i < aResult->length(); ++i )
4947         if ( const SMDS_MeshNode* n = elem->GetNode( i ))
4948           aResult[ i ] = n->GetID();
4949     }
4950   }
4951   return aResult._retn();
4952 }
4953
4954 //=============================================================================
4955 /*!
4956  * Returns true if given node is medium node
4957  * in given quadratic element
4958  */
4959 //=============================================================================
4960
4961 CORBA::Boolean SMESH_Mesh_i::IsMediumNode(const CORBA::Long ide, const CORBA::Long idn)
4962 {
4963   if ( _preMeshInfo )
4964     _preMeshInfo->FullLoadFromFile();
4965
4966   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4967   if ( aMeshDS == NULL ) return false;
4968   // try to find node
4969   const SMDS_MeshNode* aNode = aMeshDS->FindNode(idn);
4970   if(!aNode) return false;
4971   // try to find element
4972   const SMDS_MeshElement* elem = aMeshDS->FindElement(ide);
4973   if(!elem) return false;
4974
4975   return elem->IsMediumNode(aNode);
4976 }
4977
4978
4979 //=============================================================================
4980 /*!
4981  * Returns true if given node is medium node
4982  * in one of quadratic elements
4983  */
4984 //=============================================================================
4985
4986 CORBA::Boolean SMESH_Mesh_i::IsMediumNodeOfAnyElem(const CORBA::Long idn,
4987                                                    SMESH::ElementType theElemType)
4988 {
4989   if ( _preMeshInfo )
4990     _preMeshInfo->FullLoadFromFile();
4991
4992   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4993   if ( aMeshDS == NULL ) return false;
4994
4995   // try to find node
4996   const SMDS_MeshNode* aNode = aMeshDS->FindNode(idn);
4997   if(!aNode) return false;
4998
4999   SMESH_MesherHelper aHelper( *(_impl) );
5000
5001   SMDSAbs_ElementType aType;
5002   if(theElemType==SMESH::EDGE) aType = SMDSAbs_Edge;
5003   else if(theElemType==SMESH::FACE) aType = SMDSAbs_Face;
5004   else if(theElemType==SMESH::VOLUME) aType = SMDSAbs_Volume;
5005   else aType = SMDSAbs_All;
5006
5007   return aHelper.IsMedium(aNode,aType);
5008 }
5009
5010
5011 //=============================================================================
5012 /*!
5013  * Returns number of edges for given element
5014  */
5015 //=============================================================================
5016
5017 CORBA::Long SMESH_Mesh_i::ElemNbEdges(const CORBA::Long id)
5018 {
5019   if ( _preMeshInfo )
5020     _preMeshInfo->FullLoadFromFile();
5021
5022   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5023   if ( aMeshDS == NULL ) return -1;
5024   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5025   if(!elem) return -1;
5026   return elem->NbEdges();
5027 }
5028
5029
5030 //=============================================================================
5031 /*!
5032  * Returns number of faces for given element
5033  */
5034 //=============================================================================
5035
5036 CORBA::Long SMESH_Mesh_i::ElemNbFaces(const CORBA::Long id)
5037 {
5038   if ( _preMeshInfo )
5039     _preMeshInfo->FullLoadFromFile();
5040
5041   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5042   if ( aMeshDS == NULL ) return -1;
5043   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5044   if(!elem) return -1;
5045   return elem->NbFaces();
5046 }
5047
5048 //=======================================================================
5049 //function : GetElemFaceNodes
5050 //purpose  : Returns nodes of given face (counted from zero) for given element.
5051 //=======================================================================
5052
5053 SMESH::long_array* SMESH_Mesh_i::GetElemFaceNodes(CORBA::Long  elemId,
5054                                                   CORBA::Short faceIndex)
5055 {
5056   if ( _preMeshInfo )
5057     _preMeshInfo->FullLoadFromFile();
5058
5059   SMESH::long_array_var aResult = new SMESH::long_array();
5060   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() )
5061   {
5062     if ( const SMDS_MeshElement* elem = aMeshDS->FindElement(elemId) )
5063     {
5064       SMDS_VolumeTool vtool( elem, /*skipCentralNodes = */false );
5065       if ( faceIndex < vtool.NbFaces() )
5066       {
5067         aResult->length( vtool.NbFaceNodes( faceIndex ));
5068         const SMDS_MeshNode** nn = vtool.GetFaceNodes( faceIndex );
5069         for ( CORBA::ULong i = 0; i < aResult->length(); ++i )
5070           aResult[ i ] = nn[ i ]->GetID();
5071       }
5072     }
5073   }
5074   return aResult._retn();
5075 }
5076
5077 //=======================================================================
5078 //function : GetFaceNormal
5079 //purpose  : Returns three components of normal of given mesh face.
5080 //=======================================================================
5081
5082 SMESH::double_array* SMESH_Mesh_i::GetFaceNormal(CORBA::Long    elemId,
5083                                                  CORBA::Boolean normalized)
5084 {
5085   if ( _preMeshInfo )
5086     _preMeshInfo->FullLoadFromFile();
5087
5088   SMESH::double_array_var aResult = new SMESH::double_array();
5089
5090   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5091   {
5092     gp_XYZ normal;
5093     if ( SMESH_MeshAlgos::FaceNormal( mesh->FindElement(elemId), normal, normalized ))
5094     {
5095       aResult->length( 3 );
5096       aResult[ 0 ] = normal.X();
5097       aResult[ 1 ] = normal.Y();
5098       aResult[ 2 ] = normal.Z();
5099     }
5100   }
5101   return aResult._retn();
5102 }
5103
5104 //=======================================================================
5105 //function : FindElementByNodes
5106 //purpose  : Returns an element based on all given nodes.
5107 //=======================================================================
5108
5109 CORBA::Long SMESH_Mesh_i::FindElementByNodes(const SMESH::long_array& nodes)
5110 {
5111   if ( _preMeshInfo )
5112     _preMeshInfo->FullLoadFromFile();
5113
5114   CORBA::Long elemID(0);
5115   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5116   {
5117     vector< const SMDS_MeshNode * > nn( nodes.length() );
5118     for ( CORBA::ULong i = 0; i < nodes.length(); ++i )
5119       if ( !( nn[i] = mesh->FindNode( nodes[i] )))
5120         return elemID;
5121
5122     const SMDS_MeshElement* elem = mesh->FindElement( nn, SMDSAbs_All, /*noMedium=*/false );
5123     if ( !elem && ( _impl->NbEdges  ( ORDER_QUADRATIC ) ||
5124                     _impl->NbFaces  ( ORDER_QUADRATIC ) ||
5125                     _impl->NbVolumes( ORDER_QUADRATIC )))
5126       elem = mesh->FindElement( nn, SMDSAbs_All, /*noMedium=*/true );
5127
5128     if ( elem ) elemID = CORBA::Long( elem->GetID() );
5129   }
5130   return elemID;
5131 }
5132
5133 //================================================================================
5134 /*!
5135  * \brief Return elements including all given nodes.
5136  */
5137 //================================================================================
5138
5139 SMESH::long_array* SMESH_Mesh_i::GetElementsByNodes(const SMESH::long_array& nodes,
5140                                                     SMESH::ElementType       elemType)
5141 {
5142   if ( _preMeshInfo )
5143     _preMeshInfo->FullLoadFromFile();
5144
5145   SMESH::long_array_var result = new SMESH::long_array();
5146
5147   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5148   {
5149     vector< const SMDS_MeshNode * > nn( nodes.length() );
5150     for ( CORBA::ULong i = 0; i < nodes.length(); ++i )
5151       nn[i] = mesh->FindNode( nodes[i] );
5152
5153     std::vector<const SMDS_MeshElement *> elems;
5154     mesh->GetElementsByNodes( nn, elems, (SMDSAbs_ElementType) elemType );
5155     result->length( elems.size() );
5156     for ( size_t i = 0; i < elems.size(); ++i )
5157       result[i] = elems[i]->GetID();
5158   }
5159   return result._retn();
5160 }
5161
5162 //=============================================================================
5163 /*!
5164  * Returns true if given element is polygon
5165  */
5166 //=============================================================================
5167
5168 CORBA::Boolean SMESH_Mesh_i::IsPoly(const CORBA::Long id)
5169 {
5170   if ( _preMeshInfo )
5171     _preMeshInfo->FullLoadFromFile();
5172
5173   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5174   if ( aMeshDS == NULL ) return false;
5175   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5176   if(!elem) return false;
5177   return elem->IsPoly();
5178 }
5179
5180
5181 //=============================================================================
5182 /*!
5183  * Returns true if given element is quadratic
5184  */
5185 //=============================================================================
5186
5187 CORBA::Boolean SMESH_Mesh_i::IsQuadratic(const CORBA::Long id)
5188 {
5189   if ( _preMeshInfo )
5190     _preMeshInfo->FullLoadFromFile();
5191
5192   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5193   if ( aMeshDS == NULL ) return false;
5194   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5195   if(!elem) return false;
5196   return elem->IsQuadratic();
5197 }
5198
5199 //=============================================================================
5200 /*!
5201  * Returns diameter of ball discrete element or zero in case of an invalid \a id
5202  */
5203 //=============================================================================
5204
5205 CORBA::Double SMESH_Mesh_i::GetBallDiameter(CORBA::Long id)
5206 {
5207   if ( _preMeshInfo )
5208     _preMeshInfo->FullLoadFromFile();
5209
5210   if ( const SMDS_BallElement* ball =
5211        SMDS_Mesh::DownCast<SMDS_BallElement>( _impl->GetMeshDS()->FindElement( id )))
5212     return ball->GetDiameter();
5213
5214   return 0;
5215 }
5216
5217 //=============================================================================
5218 /*!
5219  * Returns bary center for given element
5220  */
5221 //=============================================================================
5222
5223 SMESH::double_array* SMESH_Mesh_i::BaryCenter(const CORBA::Long id)
5224 {
5225   if ( _preMeshInfo )
5226     _preMeshInfo->FullLoadFromFile();
5227
5228   SMESH::double_array_var aResult = new SMESH::double_array();
5229   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5230   if ( aMeshDS == NULL )
5231     return aResult._retn();
5232
5233   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5234   if(!elem)
5235     return aResult._retn();
5236
5237   if(elem->GetType()==SMDSAbs_Volume) {
5238     SMDS_VolumeTool aTool;
5239     if(aTool.Set(elem)) {
5240       aResult->length(3);
5241       if (!aTool.GetBaryCenter( aResult[0], aResult[1], aResult[2]) )
5242         aResult->length(0);
5243     }
5244   }
5245   else {
5246     SMDS_ElemIteratorPtr anIt = elem->nodesIterator();
5247     int nbn = 0;
5248     double x=0., y=0., z=0.;
5249     for(; anIt->more(); ) {
5250       nbn++;
5251       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(anIt->next());
5252       x += aNode->X();
5253       y += aNode->Y();
5254       z += aNode->Z();
5255     }
5256     if(nbn>0) {
5257       // add coordinates
5258       aResult->length(3);
5259       aResult[0] = x/nbn;
5260       aResult[1] = y/nbn;
5261       aResult[2] = z/nbn;
5262     }
5263   }
5264
5265   return aResult._retn();
5266 }
5267
5268 //================================================================================
5269 /*!
5270  * \brief Create a group of elements preventing computation of a sub-shape
5271  */
5272 //================================================================================
5273
5274 SMESH::ListOfGroups*
5275 SMESH_Mesh_i::MakeGroupsOfBadInputElements( int         theSubShapeID,
5276                                             const char* theGroupName )
5277   throw ( SALOME::SALOME_Exception )
5278 {
5279   Unexpect aCatch(SALOME_SalomeException);
5280
5281   if ( !theGroupName || strlen( theGroupName) == 0 )
5282     THROW_SALOME_CORBA_EXCEPTION( "empty group name",SALOME::BAD_PARAM );
5283
5284   SMESH::ListOfGroups_var groups = new SMESH::ListOfGroups;
5285   ::SMESH_MeshEditor::ElemFeatures elemType;
5286
5287   // submesh by subshape id
5288   if ( !_impl->HasShapeToMesh() ) theSubShapeID = 1;
5289   if ( SMESH_subMesh * sm = _impl->GetSubMeshContaining( theSubShapeID ))
5290   {
5291     // compute error
5292     SMESH_ComputeErrorPtr error = sm->GetComputeError();
5293     if ( error && error->HasBadElems() )
5294     {
5295       // sort bad elements by type
5296       vector< const SMDS_MeshElement* > elemsByType[ SMDSAbs_NbElementTypes ];
5297       const list<const SMDS_MeshElement*>& badElems =
5298         static_cast<SMESH_BadInputElements*>( error.get() )->myBadElements;
5299       list<const SMDS_MeshElement*>::const_iterator elemIt  = badElems.begin();
5300       list<const SMDS_MeshElement*>::const_iterator elemEnd = badElems.end();
5301       for ( ; elemIt != elemEnd; ++elemIt )
5302       {
5303         const SMDS_MeshElement* elem = *elemIt;
5304         if ( !elem ) continue;
5305
5306         if ( elem->GetID() < 1 )
5307         {
5308           // elem is a temporary element, make a real element
5309           vector< const SMDS_MeshNode* > nodes;
5310           SMDS_NodeIteratorPtr nIt = elem->nodeIterator();
5311           while ( nIt->more() && elem )
5312           {
5313             nodes.push_back( nIt->next() );
5314             if ( nodes.back()->GetID() < 1 )
5315               elem = 0;  // a temporary element on temporary nodes
5316           }
5317           if ( elem )
5318           {
5319             ::SMESH_MeshEditor editor( _impl );
5320             elem = editor.AddElement( nodes, elemType.Init( elem ));
5321           }
5322         }
5323         if ( elem )
5324           elemsByType[ elem->GetType() ].push_back( elem );
5325       }
5326
5327       // how many groups to create?
5328       int nbTypes = 0;
5329       for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
5330         nbTypes += int( !elemsByType[ i ].empty() );
5331       groups->length( nbTypes );
5332
5333       // create groups
5334       for ( int i = 0, iG = -1; i < SMDSAbs_NbElementTypes; ++i )
5335       {
5336         vector< const SMDS_MeshElement* >& elems = elemsByType[ i ];
5337         if ( elems.empty() ) continue;
5338
5339         groups[ ++iG ] = createGroup( SMESH::ElementType(i), theGroupName );
5340         if ( _gen_i->CanPublishInStudy( groups[ iG ] ))
5341         {
5342           SMESH::SMESH_Mesh_var mesh = _this();
5343           SALOMEDS::SObject_wrap aSO =
5344             _gen_i->PublishGroup( mesh, groups[ iG ],
5345                                  GEOM::GEOM_Object::_nil(), theGroupName);
5346         }
5347         SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( groups[ iG ]);
5348         if ( !grp_i ) continue;
5349
5350         if ( SMESHDS_Group*  grpDS = dynamic_cast< SMESHDS_Group* >( grp_i->GetGroupDS() ))
5351           for ( size_t iE = 0; iE < elems.size(); ++iE )
5352             grpDS->SMDSGroup().Add( elems[ iE ]);
5353       }
5354     }
5355   }
5356
5357   return groups._retn();
5358 }
5359
5360 //=============================================================================
5361 /*!
5362  * Create and publish group servants if any groups were imported or created anyhow
5363  */
5364 //=============================================================================
5365
5366 void SMESH_Mesh_i::CreateGroupServants()
5367 {
5368   SMESH::SMESH_Mesh_var aMesh = _this();
5369
5370   set<int> addedIDs;
5371   ::SMESH_Mesh::GroupIteratorPtr groupIt = _impl->GetGroups();
5372   while ( groupIt->more() )
5373   {
5374     ::SMESH_Group* group = groupIt->next();
5375     int             anId = group->GetID();
5376
5377     map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.find(anId);
5378     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
5379       continue;
5380     addedIDs.insert( anId );
5381
5382     SMESH_GroupBase_i* aGroupImpl;
5383     TopoDS_Shape       shape;
5384     if ( SMESHDS_GroupOnGeom* groupOnGeom =
5385          dynamic_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() ))
5386     {
5387       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
5388       shape      = groupOnGeom->GetShape();
5389     }
5390     else {
5391       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
5392     }
5393
5394     SMESH::SMESH_GroupBase_var groupVar = aGroupImpl->_this();
5395     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( groupVar );
5396     aGroupImpl->Register();
5397
5398     // register CORBA object for persistence
5399     int nextId = _gen_i->RegisterObject( groupVar );
5400     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
5401     else        { nextId = 0; } // avoid "unused variable" warning in release mode
5402
5403     // publishing the groups in the study
5404     GEOM::GEOM_Object_var shapeVar = _gen_i->ShapeToGeomObject( shape );
5405     _gen_i->PublishGroup( aMesh, groupVar, shapeVar, group->GetName());
5406   }
5407   if ( !addedIDs.empty() )
5408   {
5409     // python dump
5410     set<int>::iterator id = addedIDs.begin();
5411     for ( ; id != addedIDs.end(); ++id )
5412     {
5413       map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.find(*id);
5414       int i = std::distance( _mapGroups.begin(), it );
5415       TPythonDump() << it->second << " = " << aMesh << ".GetGroups()[ "<< i << " ]";
5416     }
5417   }
5418 }
5419
5420 //=============================================================================
5421 /*!
5422  * \brief Return true if all sub-meshes are computed OK - to update an icon
5423  */
5424 //=============================================================================
5425
5426 bool SMESH_Mesh_i::IsComputedOK()
5427 {
5428   return _impl->IsComputedOK();
5429 }
5430
5431 //=============================================================================
5432 /*!
5433  * \brief Return groups cantained in _mapGroups by their IDs
5434  */
5435 //=============================================================================
5436
5437 SMESH::ListOfGroups* SMESH_Mesh_i::GetGroups(const list<int>& groupIDs) const
5438 {
5439   int nbGroups = groupIDs.size();
5440   SMESH::ListOfGroups_var aList = new SMESH::ListOfGroups();
5441   aList->length( nbGroups );
5442
5443   list<int>::const_iterator ids = groupIDs.begin();
5444   for ( nbGroups = 0; ids != groupIDs.end(); ++ids )
5445   {
5446     map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator it = _mapGroups.find( *ids );
5447     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
5448       aList[nbGroups++] = SMESH::SMESH_GroupBase::_duplicate( it->second );
5449   }
5450   aList->length( nbGroups );
5451   return aList._retn();
5452 }
5453
5454 //=============================================================================
5455 /*!
5456  * \brief Return information about imported file
5457  */
5458 //=============================================================================
5459
5460 SMESH::MedFileInfo* SMESH_Mesh_i::GetMEDFileInfo()
5461 {
5462   SMESH::MedFileInfo_var res( _medFileInfo );
5463   if ( !res.operator->() ) {
5464     res = new SMESH::MedFileInfo;
5465     res->fileName = "";
5466     res->fileSize = res->major = res->minor = res->release = -1;
5467   }
5468   return res._retn();
5469 }
5470
5471 //=======================================================================
5472 //function : FileInfoToString
5473 //purpose  : Persistence of file info
5474 //=======================================================================
5475
5476 std::string SMESH_Mesh_i::FileInfoToString()
5477 {
5478   std::string s;
5479   if ( &_medFileInfo.in() && _medFileInfo->fileName[0] )
5480   {
5481     s = SMESH_Comment( _medFileInfo->fileSize )
5482       << " " << _medFileInfo->major
5483       << " " << _medFileInfo->minor
5484       << " " << _medFileInfo->release
5485       << " " << _medFileInfo->fileName;
5486   }
5487   return s;
5488 }
5489
5490 //=======================================================================
5491 //function : FileInfoFromString
5492 //purpose  : Persistence of file info
5493 //=======================================================================
5494
5495 void SMESH_Mesh_i::FileInfoFromString(const std::string& info)
5496 {
5497   std::string size, major, minor, release, fileName;
5498   std::istringstream is(info);
5499   is >> size >> major >> minor >> release;
5500   fileName = info.data() + ( size.size()   + 1 +
5501                              major.size()  + 1 +
5502                              minor.size()  + 1 +
5503                              release.size()+ 1 );
5504
5505   _medFileInfo           = new SMESH::MedFileInfo();
5506   _medFileInfo->fileName = fileName.c_str();
5507   _medFileInfo->fileSize = atoi( size.c_str() );
5508   _medFileInfo->major    = atoi( major.c_str() );
5509   _medFileInfo->minor    = atoi( minor.c_str() );
5510   _medFileInfo->release  = atoi( release.c_str() );
5511 }
5512
5513 //=============================================================================
5514 /*!
5515  * \brief Pass names of mesh groups from study to mesh DS
5516  */
5517 //=============================================================================
5518
5519 void SMESH_Mesh_i::checkGroupNames()
5520 {
5521   int nbGrp = NbGroups();
5522   if ( !nbGrp )
5523     return;
5524
5525   SMESH::ListOfGroups* grpList = 0;
5526   // avoid dump of "GetGroups"
5527   {
5528     // store python dump into a local variable inside local scope
5529     SMESH::TPythonDump pDump; // do not delete this line of code
5530     grpList = GetGroups();
5531   }
5532
5533   for ( int gIndx = 0; gIndx < nbGrp; gIndx++ ) {
5534     SMESH::SMESH_GroupBase_ptr aGrp = (*grpList)[ gIndx ];
5535     if ( !aGrp )
5536       continue;
5537     SALOMEDS::SObject_wrap aGrpSO = _gen_i->ObjectToSObject( aGrp );
5538     if ( aGrpSO->_is_nil() )
5539       continue;
5540     // correct name of the mesh group if necessary
5541     const char* guiName = aGrpSO->GetName();
5542     if ( strcmp(guiName, aGrp->GetName()) )
5543       aGrp->SetName( guiName );
5544   }
5545 }
5546
5547 //=============================================================================
5548 /*!
5549  * \brief Sets list of notebook variables used for Mesh operations separated by ":" symbol
5550  */
5551 //=============================================================================
5552 void SMESH_Mesh_i::SetParameters(const char* theParameters)
5553 {
5554   SMESH_Gen_i::GetSMESHGen()->UpdateParameters( CORBA::Object_var( _this() ).in(),
5555                                                 theParameters );
5556 }
5557
5558 //=============================================================================
5559 /*!
5560  * \brief Returns list of notebook variables used for Mesh operations separated by ":" symbol
5561  */
5562 //=============================================================================
5563
5564 char* SMESH_Mesh_i::GetParameters()
5565 {
5566   return SMESH_Gen_i::GetSMESHGen()->GetParameters( SMESH::SMESH_Mesh_var( _this()) );
5567 }
5568
5569 //=============================================================================
5570 /*!
5571  * \brief Returns list of notebook variables used for last Mesh operation
5572  */
5573 //=============================================================================
5574 SMESH::string_array* SMESH_Mesh_i::GetLastParameters()
5575 {
5576   SMESH::string_array_var aResult = new SMESH::string_array();
5577   SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen();
5578   if(gen) {
5579     CORBA::String_var aParameters = GetParameters();
5580     SALOMEDS::ListOfListOfStrings_var aSections = SMESH_Gen_i::getStudyServant()->ParseVariables(aParameters);
5581     if ( aSections->length() > 0 ) {
5582       SALOMEDS::ListOfStrings aVars = aSections[ aSections->length() - 1 ];
5583       aResult->length( aVars.length() );
5584       for ( CORBA::ULong i = 0;i < aVars.length(); i++ )
5585         aResult[i] = CORBA::string_dup( aVars[i] );
5586     }
5587   }
5588   return aResult._retn();
5589 }
5590
5591 //=======================================================================
5592 //function : GetTypes
5593 //purpose  : Returns types of elements it contains
5594 //=======================================================================
5595
5596 SMESH::array_of_ElementType* SMESH_Mesh_i::GetTypes()
5597 {
5598   if ( _preMeshInfo )
5599     return _preMeshInfo->GetTypes();
5600
5601   SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType;
5602
5603   types->length( 5 );
5604   int nbTypes = 0;
5605   if (_impl->NbEdges())      types[nbTypes++] = SMESH::EDGE;
5606   if (_impl->NbFaces())      types[nbTypes++] = SMESH::FACE;
5607   if (_impl->NbVolumes())    types[nbTypes++] = SMESH::VOLUME;
5608   if (_impl->Nb0DElements()) types[nbTypes++] = SMESH::ELEM0D;
5609   if (_impl->NbBalls())      types[nbTypes++] = SMESH::BALL;
5610   if (_impl->NbNodes() &&
5611       nbTypes == 0 )         types[nbTypes++] = SMESH::NODE;
5612   types->length( nbTypes );
5613
5614   return types._retn();
5615 }
5616
5617 //=======================================================================
5618 //function : GetMesh
5619 //purpose  : Returns self
5620 //=======================================================================
5621
5622 SMESH::SMESH_Mesh_ptr SMESH_Mesh_i::GetMesh()
5623 {
5624   return SMESH::SMESH_Mesh::_duplicate( _this() );
5625 }
5626
5627 //=======================================================================
5628 //function : IsMeshInfoCorrect
5629 //purpose  : * Returns false if GetMeshInfo() returns incorrect information that may
5630 //           * happen if mesh data is not yet fully loaded from the file of study.
5631 //=======================================================================
5632
5633 bool SMESH_Mesh_i::IsMeshInfoCorrect()
5634 {
5635   return _preMeshInfo ? _preMeshInfo->IsMeshInfoCorrect() : true;
5636 }
5637
5638 //=============================================================================
5639 /*!
5640  * \brief Returns number of mesh elements per each \a EntityType
5641  */
5642 //=============================================================================
5643
5644 SMESH::long_array* SMESH_Mesh_i::GetMeshInfo()
5645 {
5646   if ( _preMeshInfo )
5647     return _preMeshInfo->GetMeshInfo();
5648
5649   SMESH::long_array_var aRes = new SMESH::long_array();
5650   aRes->length(SMESH::Entity_Last);
5651   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
5652     aRes[i] = 0;
5653   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5654   if (!aMeshDS)
5655     return aRes._retn();
5656   const SMDS_MeshInfo& aMeshInfo = aMeshDS->GetMeshInfo();
5657   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
5658     aRes[i] = aMeshInfo.NbEntities((SMDSAbs_EntityType)i);
5659   return aRes._retn();
5660 }
5661
5662 //=============================================================================
5663 /*!
5664  * \brief Returns number of mesh elements per each \a ElementType
5665  */
5666 //=============================================================================
5667
5668 SMESH::long_array* SMESH_Mesh_i::GetNbElementsByType()
5669 {
5670   SMESH::long_array_var aRes = new SMESH::long_array();
5671   aRes->length(SMESH::NB_ELEMENT_TYPES);
5672   for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
5673     aRes[ i ] = 0;
5674
5675   const SMDS_MeshInfo* meshInfo = 0;
5676   if ( _preMeshInfo )
5677     meshInfo = _preMeshInfo;
5678   else if ( SMESHDS_Mesh* meshDS = _impl->GetMeshDS() )
5679     meshInfo = & meshDS->GetMeshInfo();
5680
5681   if (meshInfo)
5682     for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
5683       aRes[i] = meshInfo->NbElements((SMDSAbs_ElementType)i);
5684
5685   return aRes._retn();
5686 }
5687
5688 //=============================================================================
5689 /*
5690  * Collect statistic of mesh elements given by iterator
5691  */
5692 //=============================================================================
5693
5694 void SMESH_Mesh_i::CollectMeshInfo(const SMDS_ElemIteratorPtr theItr,
5695                                    SMESH::long_array&         theInfo)
5696 {
5697   if (!theItr) return;
5698   while (theItr->more())
5699     theInfo[ theItr->next()->GetEntityType() ]++;
5700 }
5701 //=============================================================================
5702 /*
5703  * Returns mesh unstructed grid information.
5704  */
5705 //=============================================================================
5706
5707 SALOMEDS::TMPFile* SMESH_Mesh_i::GetVtkUgStream()
5708 {
5709   SALOMEDS::TMPFile_var SeqFile;
5710   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() ) {
5711     SMDS_UnstructuredGrid* aGrid = aMeshDS->GetGrid();
5712     if(aGrid) {
5713       vtkUnstructuredGridWriter* aWriter = vtkUnstructuredGridWriter::New();
5714       aWriter->WriteToOutputStringOn();
5715       aWriter->SetInputData(aGrid);
5716       aWriter->SetFileTypeToBinary();
5717       aWriter->Write();
5718       char* str = aWriter->GetOutputString();
5719       int size = aWriter->GetOutputStringLength();
5720
5721       //Allocate octet buffer of required size
5722       CORBA::Octet* OctetBuf = SALOMEDS::TMPFile::allocbuf(size);
5723       //Copy ostrstream content to the octet buffer
5724       memcpy(OctetBuf, str, size);
5725       //Create and return TMPFile
5726       SeqFile = new SALOMEDS::TMPFile(size, size, OctetBuf, 1);
5727       aWriter->Delete();
5728     }
5729   }
5730   return SeqFile._retn();
5731 }
5732
5733 //=============================================================================
5734 namespace /* Iterators used in SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_var obj,
5735            *                                             SMESH::ElementType        type) */
5736 {
5737   using namespace SMESH::Controls;
5738   //-----------------------------------------------------------------------------
5739   struct PredicateIterator : public SMDS_ElemIterator
5740   {
5741     SMDS_ElemIteratorPtr    _elemIter;
5742     PredicatePtr            _predicate;
5743     const SMDS_MeshElement* _elem;
5744     SMDSAbs_ElementType     _type;
5745
5746     PredicateIterator( SMDS_ElemIteratorPtr iterator,
5747                        PredicatePtr         predicate,
5748                        SMDSAbs_ElementType  type):
5749       _elemIter(iterator), _predicate(predicate), _type(type)
5750     {
5751       next();
5752     }
5753     virtual bool more()
5754     {
5755       return _elem;
5756     }
5757     virtual const SMDS_MeshElement* next()
5758     {
5759       const SMDS_MeshElement* res = _elem;
5760       _elem = 0;
5761       while ( _elemIter->more() && !_elem )
5762       {
5763         if ((_elem = _elemIter->next()) &&
5764             (( _type != SMDSAbs_All && _type != _elem->GetType() ) ||
5765              ( !_predicate->IsSatisfy( _elem->GetID() ))))
5766           _elem = 0;
5767       }
5768       return res;
5769     }
5770   };
5771
5772   //-----------------------------------------------------------------------------
5773   struct IDSourceIterator : public SMDS_ElemIterator
5774   {
5775     const CORBA::Long*        _idPtr;
5776     const CORBA::Long*        _idEndPtr;
5777     SMESH::long_array_var     _idArray;
5778     const SMDS_Mesh*          _mesh;
5779     const SMDSAbs_ElementType _type;
5780     const SMDS_MeshElement*   _elem;
5781
5782     IDSourceIterator( const SMDS_Mesh*    mesh,
5783                       const CORBA::Long*  ids,
5784                       const int           nbIds,
5785                       SMDSAbs_ElementType type):
5786       _idPtr( ids ), _idEndPtr( ids + nbIds ), _mesh( mesh ), _type( type ), _elem( 0 )
5787     {
5788       if ( _idPtr && nbIds && _mesh )
5789         next();
5790     }
5791     IDSourceIterator( const SMDS_Mesh*    mesh,
5792                       SMESH::long_array*  idArray,
5793                       SMDSAbs_ElementType type):
5794       _idPtr( 0 ), _idEndPtr( 0 ), _idArray( idArray), _mesh( mesh ), _type( type ), _elem( 0 )
5795     {
5796       if ( idArray && _mesh )
5797       {
5798         _idPtr    = &_idArray[0];
5799         _idEndPtr = _idPtr + _idArray->length();
5800         next();
5801       }
5802     }
5803     virtual bool more()
5804     {
5805       return _elem;
5806     }
5807     virtual const SMDS_MeshElement* next()
5808     {
5809       const SMDS_MeshElement* res = _elem;
5810       _elem = 0;
5811       while ( _idPtr < _idEndPtr && !_elem )
5812       {
5813         if ( _type == SMDSAbs_Node )
5814         {
5815           _elem = _mesh->FindNode( *_idPtr++ );
5816         }
5817         else if ((_elem = _mesh->FindElement( *_idPtr++ )) &&
5818                  (_elem->GetType() != _type && _type != SMDSAbs_All ))
5819         {
5820           _elem = 0;
5821         }
5822       }
5823       return res;
5824     }
5825   };
5826   //-----------------------------------------------------------------------------
5827
5828   struct NodeOfElemIterator : public SMDS_ElemIterator
5829   {
5830     TColStd_MapOfInteger    _checkedNodeIDs;
5831     SMDS_ElemIteratorPtr    _elemIter;
5832     SMDS_ElemIteratorPtr    _nodeIter;
5833     const SMDS_MeshElement* _node;
5834
5835     NodeOfElemIterator( SMDS_ElemIteratorPtr iter ): _elemIter( iter ), _node( 0 )
5836     {
5837       if ( _elemIter && _elemIter->more() )
5838       {
5839         _nodeIter = _elemIter->next()->nodesIterator();
5840         next();
5841       }
5842     }
5843     virtual bool more()
5844     {
5845       return _node;
5846     }
5847     virtual const SMDS_MeshElement* next()
5848     {
5849       const SMDS_MeshElement* res = _node;
5850       _node = 0;
5851       while ( !_node && ( _elemIter->more() || _nodeIter->more() ))
5852       {
5853         if ( _nodeIter->more() )
5854         {
5855           _node = _nodeIter->next();
5856           if ( !_checkedNodeIDs.Add( _node->GetID() ))
5857             _node = 0;
5858         }
5859         else
5860         {
5861           _nodeIter = _elemIter->next()->nodesIterator();
5862         }
5863       }
5864       return res;
5865     }
5866   };
5867 }
5868
5869 //=============================================================================
5870 /*
5871  * Return iterator on elements of given type in given object
5872  */
5873 //=============================================================================
5874
5875 SMDS_ElemIteratorPtr SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_ptr theObject,
5876                                                SMESH::ElementType        theType)
5877 {
5878   SMDS_ElemIteratorPtr  elemIt;
5879   bool                  typeOK = ( theType == SMESH::ALL );
5880   SMDSAbs_ElementType elemType = SMDSAbs_ElementType( theType );
5881
5882   SMESH::SMESH_Mesh_var meshVar = theObject->GetMesh();
5883   SMESH_Mesh_i*          mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( meshVar );
5884   if ( !mesh_i ) return elemIt;
5885   SMESHDS_Mesh*          meshDS = mesh_i->GetImpl().GetMeshDS();
5886
5887   if ( SMESH::DownCast<SMESH_Mesh_i*>( theObject ))
5888   {
5889     elemIt = meshDS->elementsIterator( elemType );
5890     typeOK = true;
5891   }
5892   else if ( SMESH_subMesh_i* submesh_i = SMESH::DownCast<SMESH_subMesh_i*>( theObject ))
5893   {
5894     SMESHDS_SubMesh* sm = ((SMESHDS_Mesh*) meshDS)->MeshElements( submesh_i->GetId() );
5895     if ( sm )
5896     {
5897       elemIt = sm->GetElements();
5898       if ( elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
5899       {
5900         typeOK = ( elemIt && elemIt->more() && elemIt->next()->GetType() == elemType );
5901         elemIt = typeOK ? sm->GetElements() : SMDS_ElemIteratorPtr();
5902       }
5903     }
5904   }
5905   else if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( theObject ))
5906   {
5907     SMESHDS_GroupBase* groupDS = group_i->GetGroupDS();
5908     if ( groupDS && ( elemType == groupDS->GetType()  ||
5909                       elemType == SMDSAbs_Node ||
5910                       elemType == SMDSAbs_All ))
5911     {
5912       elemIt = groupDS->GetElements();
5913       typeOK = ( groupDS->GetType() == elemType || elemType == SMDSAbs_All );
5914     }
5915   }
5916   else if ( SMESH::Filter_i* filter_i = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
5917   {
5918     if ( filter_i->GetElementType() == theType ||
5919          filter_i->GetElementType() == SMESH::ALL ||
5920          elemType == SMDSAbs_Node ||
5921          elemType == SMDSAbs_All)
5922     {
5923       SMESH::Predicate_i* pred_i = filter_i->GetPredicate_i();
5924       if ( pred_i && pred_i->GetPredicate() )
5925       {
5926         SMDSAbs_ElementType filterType = SMDSAbs_ElementType( filter_i->GetElementType() );
5927         SMDS_ElemIteratorPtr allElemIt = meshDS->elementsIterator( filterType );
5928         SMDSAbs_ElementType   iterType = elemType == SMDSAbs_Node ? filterType : elemType;
5929         elemIt = SMDS_ElemIteratorPtr
5930           ( new PredicateIterator( allElemIt, pred_i->GetPredicate(), iterType ));
5931         typeOK = ( elemType == SMDSAbs_Node ? filterType == SMDSAbs_Node : elemIt->more() );
5932       }
5933     }
5934   }
5935   else
5936   {
5937     SMESH::array_of_ElementType_var types = theObject->GetTypes();
5938     const bool                    isNodes = ( types->length() == 1 && types[0] == SMESH::NODE );
5939     if ( isNodes && elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
5940       return elemIt;
5941     SMDSAbs_ElementType iterType = isNodes ? SMDSAbs_Node : elemType;
5942     if ( SMESH_MeshEditor_i::IsTemporaryIDSource( theObject ))
5943     {
5944       int nbIds;
5945       if ( CORBA::Long* ids = SMESH_MeshEditor_i::GetTemporaryIDs( theObject, nbIds ))
5946         elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids, nbIds, iterType ));
5947     }
5948     else
5949     {
5950       SMESH::long_array_var ids = theObject->GetIDs();
5951       elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids._retn(), iterType ));
5952     }
5953     typeOK = ( isNodes == ( elemType == SMDSAbs_Node )) || ( elemType == SMDSAbs_All );
5954   }
5955
5956   if ( elemIt && elemIt->more() && !typeOK )
5957   {
5958     if ( elemType == SMDSAbs_Node )
5959     {
5960       elemIt = SMDS_ElemIteratorPtr( new NodeOfElemIterator( elemIt ));
5961     }
5962     else
5963     {
5964       elemIt = SMDS_ElemIteratorPtr();
5965     }
5966   }
5967   return elemIt;
5968 }
5969
5970 //=============================================================================
5971 namespace // Finding concurrent hypotheses
5972 //=============================================================================
5973 {
5974
5975 /*!
5976  * \brief mapping of mesh dimension into shape type
5977  */
5978 TopAbs_ShapeEnum shapeTypeByDim(const int theDim)
5979 {
5980   TopAbs_ShapeEnum aType = TopAbs_SOLID;
5981   switch ( theDim ) {
5982   case 0: aType = TopAbs_VERTEX; break;
5983   case 1: aType = TopAbs_EDGE; break;
5984   case 2: aType = TopAbs_FACE; break;
5985   case 3:
5986   default:aType = TopAbs_SOLID; break;
5987   }
5988   return aType;
5989 }
5990
5991 //-----------------------------------------------------------------------------
5992 /*!
5993  * \brief Internal structure used to find concurrent submeshes
5994  *
5995  * It represents a pair < submesh, concurrent dimension >, where
5996  * 'concurrent dimension' is dimension of shape where the submesh can concurrent
5997  *  with another submesh. In other words, it is dimension of a hypothesis assigned
5998  *  to submesh.
5999  */
6000 class SMESH_DimHyp
6001 {
6002  public:
6003   //! fields
6004   int _dim;    //!< a dimension the algo can build (concurrent dimension)
6005   int _ownDim; //!< dimension of shape of _subMesh (>=_dim)
6006   TopTools_MapOfShape _shapeMap;
6007   SMESH_subMesh*      _subMesh;
6008   list<const SMESHDS_Hypothesis*> _hypotheses; //!< algo is first, then its parameters
6009
6010   //-----------------------------------------------------------------------------
6011   // Return the algorithm
6012   const SMESH_Algo* GetAlgo() const
6013   { return _hypotheses.empty() ? 0 : dynamic_cast<const SMESH_Algo*>( _hypotheses.front() ); }
6014
6015   //-----------------------------------------------------------------------------
6016   //! Constructors
6017   SMESH_DimHyp(const SMESH_subMesh* theSubMesh,
6018                const int            theDim,
6019                const TopoDS_Shape&  theShape)
6020   {
6021     _subMesh = (SMESH_subMesh*)theSubMesh;
6022     SetShape( theDim, theShape );
6023   }
6024
6025   //-----------------------------------------------------------------------------
6026   //! set shape
6027   void SetShape(const int           theDim,
6028                 const TopoDS_Shape& theShape)
6029   {
6030     _dim = theDim;
6031     _ownDim = SMESH_Gen::GetShapeDim(theShape);
6032     if (_dim >= _ownDim)
6033       _shapeMap.Add( theShape );
6034     else {
6035       TopExp_Explorer anExp( theShape, shapeTypeByDim(theDim) );
6036       for( ; anExp.More(); anExp.Next() )
6037         _shapeMap.Add( anExp.Current() );
6038     }
6039   }
6040
6041   //-----------------------------------------------------------------------------
6042   //! Check sharing of sub-shapes
6043   static bool isShareSubShapes(const TopTools_MapOfShape& theToCheck,
6044                                const TopTools_MapOfShape& theToFind,
6045                                const TopAbs_ShapeEnum     theType)
6046   {
6047     bool isShared = false;
6048     TopTools_MapIteratorOfMapOfShape anItr( theToCheck );
6049     for (; !isShared && anItr.More(); anItr.Next() )
6050     {
6051       const TopoDS_Shape aSubSh = anItr.Key();
6052       // check for case when concurrent dimensions are same
6053       isShared = theToFind.Contains( aSubSh );
6054       // check for sub-shape with concurrent dimension
6055       TopExp_Explorer anExp( aSubSh, theType );
6056       for ( ; !isShared && anExp.More(); anExp.Next() )
6057         isShared = theToFind.Contains( anExp.Current() );
6058     }
6059     return isShared;
6060   }
6061
6062   //-----------------------------------------------------------------------------
6063   //! check algorithms
6064   static bool checkAlgo(const SMESHDS_Hypothesis* theA1,
6065                         const SMESHDS_Hypothesis* theA2)
6066   {
6067     if ( !theA1 || !theA2 ||
6068          theA1->GetType() == SMESHDS_Hypothesis::PARAM_ALGO ||
6069          theA2->GetType() == SMESHDS_Hypothesis::PARAM_ALGO )
6070       return false; // one of the hypothesis is not algorithm
6071     // check algorithm names (should be equal)
6072     return strcmp( theA1->GetName(), theA2->GetName() ) == 0;
6073   }
6074
6075
6076   //-----------------------------------------------------------------------------
6077   //! Check if sub-shape hypotheses are concurrent
6078   bool IsConcurrent(const SMESH_DimHyp* theOther) const
6079   {
6080     if ( _subMesh == theOther->_subMesh )
6081       return false; // same sub-shape - should not be
6082
6083     // if ( <own dim of either of submeshes> == <concurrent dim> &&
6084     //      any of the two submeshes is not on COMPOUND shape )
6085     //  -> no concurrency
6086     bool meIsCompound    = (_subMesh->GetSubMeshDS() &&
6087                             _subMesh->GetSubMeshDS()->IsComplexSubmesh());
6088     bool otherIsCompound = (theOther->_subMesh->GetSubMeshDS() &&
6089                             theOther->_subMesh->GetSubMeshDS()->IsComplexSubmesh());
6090     if ( (_ownDim == _dim  || theOther->_ownDim == _dim ) && (!meIsCompound || !otherIsCompound))
6091       return false;
6092
6093     bool checkSubShape = isShareSubShapes( _shapeMap, theOther->_shapeMap, shapeTypeByDim(_dim));
6094     if ( !checkSubShape )
6095       return false;
6096
6097     // check algorithms to be same
6098     const SMESH_Algo* a1 = this->GetAlgo();
6099     const SMESH_Algo* a2 = theOther->GetAlgo();
6100     bool isSame = checkAlgo( a1, a2 );
6101     if ( !isSame )
6102     {
6103       if ( !a1 || !a2 )
6104         return false; // pb?
6105       return a1->GetDim() == a2->GetDim(); // different algorithms of same dim -> concurrency !
6106     }
6107
6108     // check hypothesises for concurrence (skip first as algorithm)
6109     size_t nbSame = 0;
6110     // pointers should be same, because it is referened from mesh hypothesis partition
6111     list <const SMESHDS_Hypothesis*>::const_iterator hypIt = _hypotheses.begin();
6112     list <const SMESHDS_Hypothesis*>::const_iterator otheEndIt = theOther->_hypotheses.end();
6113     for ( hypIt++ /*skip first as algo*/; hypIt != _hypotheses.end(); hypIt++ )
6114       if ( find( theOther->_hypotheses.begin(), otheEndIt, *hypIt ) != otheEndIt )
6115         nbSame++;
6116     // the submeshes are concurrent if their algorithms has different parameters
6117     return nbSame != theOther->_hypotheses.size() - 1;
6118   }
6119
6120   // Return true if algorithm of this SMESH_DimHyp is used if no
6121   // sub-mesh order is imposed by the user
6122   bool IsHigherPriorityThan( const SMESH_DimHyp* theOther ) const
6123   {
6124     // NeedDiscreteBoundary() algo has a higher priority
6125     if ( this    ->GetAlgo()->NeedDiscreteBoundary() !=
6126          theOther->GetAlgo()->NeedDiscreteBoundary() )
6127       return !this->GetAlgo()->NeedDiscreteBoundary();
6128
6129     return ( this->_subMesh->GetId() < theOther->_subMesh->GetId() );
6130   }
6131
6132 }; // end of SMESH_DimHyp
6133 //-----------------------------------------------------------------------------
6134
6135 typedef list<const SMESH_DimHyp*> TDimHypList;
6136
6137 //-----------------------------------------------------------------------------
6138
6139 void addDimHypInstance(const int                               theDim,
6140                        const TopoDS_Shape&                     theShape,
6141                        const SMESH_Algo*                       theAlgo,
6142                        const SMESH_subMesh*                    theSubMesh,
6143                        const list <const SMESHDS_Hypothesis*>& theHypList,
6144                        TDimHypList*                            theDimHypListArr )
6145 {
6146   TDimHypList& listOfdimHyp = theDimHypListArr[theDim];
6147   if ( listOfdimHyp.empty() || listOfdimHyp.back()->_subMesh != theSubMesh ) {
6148     SMESH_DimHyp* dimHyp = new SMESH_DimHyp( theSubMesh, theDim, theShape );
6149     dimHyp->_hypotheses.push_front(theAlgo);
6150     listOfdimHyp.push_back( dimHyp );
6151   }
6152
6153   SMESH_DimHyp* dimHyp = const_cast<SMESH_DimHyp*>( listOfdimHyp.back() );
6154   dimHyp->_hypotheses.insert( dimHyp->_hypotheses.end(),
6155                               theHypList.begin(), theHypList.end() );
6156 }
6157
6158 //-----------------------------------------------------------------------------
6159 void addInOrderOfPriority( const SMESH_DimHyp* theDimHyp,
6160                            TDimHypList&        theListOfConcurr)
6161 {
6162   if ( theListOfConcurr.empty() )
6163   {
6164     theListOfConcurr.push_back( theDimHyp );
6165   }
6166   else
6167   {
6168     TDimHypList::iterator hypIt = theListOfConcurr.begin();
6169     while ( hypIt != theListOfConcurr.end() &&
6170             !theDimHyp->IsHigherPriorityThan( *hypIt ))
6171       ++hypIt;
6172     theListOfConcurr.insert( hypIt, theDimHyp );
6173   }
6174 }
6175
6176 //-----------------------------------------------------------------------------
6177 void findConcurrents(const SMESH_DimHyp* theDimHyp,
6178                      const TDimHypList&  theListOfDimHyp,
6179                      TDimHypList&        theListOfConcurrHyp,
6180                      set<int>&           theSetOfConcurrId )
6181 {
6182   TDimHypList::const_reverse_iterator rIt = theListOfDimHyp.rbegin();
6183   for ( ; rIt != theListOfDimHyp.rend(); rIt++ )
6184   {
6185     const SMESH_DimHyp* curDimHyp = *rIt;
6186     if ( curDimHyp == theDimHyp )
6187       break; // meet own dimHyp pointer in same dimension
6188
6189     if ( theDimHyp->IsConcurrent( curDimHyp ) &&
6190          theSetOfConcurrId.insert( curDimHyp->_subMesh->GetId() ).second )
6191     {
6192       addInOrderOfPriority( curDimHyp, theListOfConcurrHyp );
6193     }
6194   }
6195 }
6196
6197 //-----------------------------------------------------------------------------
6198 void unionLists(TListOfInt&       theListOfId,
6199                 TListOfListOfInt& theListOfListOfId,
6200                 const int         theIndx )
6201 {
6202   TListOfListOfInt::iterator it = theListOfListOfId.begin();
6203   for ( int i = 0; it != theListOfListOfId.end(); it++, i++ ) {
6204     if ( i < theIndx )
6205       continue; //skip already treated lists
6206     // check if other list has any same submesh object
6207     TListOfInt& otherListOfId = *it;
6208     if ( find_first_of( theListOfId.begin(), theListOfId.end(),
6209                         otherListOfId.begin(), otherListOfId.end() ) == theListOfId.end() )
6210       continue;
6211
6212     // union two lists (from source into target)
6213     TListOfInt::iterator it2 = otherListOfId.begin();
6214     for ( ; it2 != otherListOfId.end(); it2++ ) {
6215       if ( find( theListOfId.begin(), theListOfId.end(), (*it2) ) == theListOfId.end() )
6216         theListOfId.push_back(*it2);
6217     }
6218     // clear source list
6219     otherListOfId.clear();
6220   }
6221 }
6222 //-----------------------------------------------------------------------------
6223
6224 //! free memory allocated for dimension-hypothesis objects
6225 void removeDimHyps( TDimHypList* theArrOfList )
6226 {
6227   for (int i = 0; i < 4; i++ ) {
6228     TDimHypList& listOfdimHyp = theArrOfList[i];
6229     TDimHypList::const_iterator it = listOfdimHyp.begin();
6230     for ( ; it != listOfdimHyp.end(); it++ )
6231       delete (*it);
6232   }
6233 }
6234
6235 //-----------------------------------------------------------------------------
6236 /*!
6237  * \brief find common submeshes with given submesh
6238  * \param theSubMeshList list of already collected submesh to check
6239  * \param theSubMesh given submesh to intersect with other
6240  * \param theCommonSubMeshes collected common submeshes
6241  */
6242 void findCommonSubMesh (list<const SMESH_subMesh*>& theSubMeshList,
6243                         const SMESH_subMesh*        theSubMesh,
6244                         set<const SMESH_subMesh*>&  theCommon )
6245 {
6246   if ( !theSubMesh )
6247     return;
6248   list<const SMESH_subMesh*>::const_iterator it = theSubMeshList.begin();
6249   for ( ; it != theSubMeshList.end(); it++ )
6250     theSubMesh->FindIntersection( *it, theCommon );
6251   theSubMeshList.push_back( theSubMesh );
6252   //theCommon.insert( theSubMesh );
6253 }
6254
6255 //-----------------------------------------------------------------------------
6256 bool isSubMeshInList ( int smID, const TListOfListOfInt& smLists )
6257 {
6258   TListOfListOfInt::const_iterator listsIt = smLists.begin();
6259   for ( ; listsIt != smLists.end(); ++listsIt )
6260   {
6261     const TListOfInt& smIDs = *listsIt;
6262     if ( std::find( smIDs.begin(), smIDs.end(), smID ) != smIDs.end() )
6263       return true;
6264   }
6265   return false;
6266 }
6267
6268 } // namespace
6269
6270 //=============================================================================
6271 /*!
6272  * \brief Return \c true if a meshing order not yet set for a concurrent sub-mesh
6273  */
6274 //=============================================================================
6275
6276 CORBA::Boolean SMESH_Mesh_i::IsUnorderedSubMesh(CORBA::Long submeshID)
6277 {
6278   TListOfListOfInt anOrder = GetImpl().GetMeshOrder(); // already defined order
6279   if ( isSubMeshInList( submeshID, anOrder ))
6280     return false;
6281
6282   TListOfListOfInt allConurrent = findConcurrentSubMeshes();
6283   return isSubMeshInList( submeshID, allConurrent );
6284 }
6285
6286 //=============================================================================
6287 /*!
6288  * \brief Return submesh objects list in meshing order
6289  */
6290 //=============================================================================
6291
6292 SMESH::submesh_array_array* SMESH_Mesh_i::GetMeshOrder()
6293 {
6294   SMESH::submesh_array_array_var aResult = new SMESH::submesh_array_array();
6295
6296   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
6297   if ( !aMeshDS )
6298     return aResult._retn();
6299
6300   TListOfListOfInt      anOrder = GetImpl().GetMeshOrder(); // already defined order
6301   TListOfListOfInt allConurrent = findConcurrentSubMeshes();
6302   anOrder.splice( anOrder.end(), allConurrent );
6303
6304   int listIndx = 0;
6305   TListOfListOfInt::iterator listIt = anOrder.begin();
6306   for(; listIt != anOrder.end(); listIt++, listIndx++ )
6307     unionLists( *listIt,  anOrder, listIndx + 1 );
6308
6309   // convert submesh ids into interface instances
6310   //  and dump command into python
6311   convertMeshOrder( anOrder, aResult, false );
6312
6313   return aResult._retn();
6314 }
6315
6316 //=============================================================================
6317 /*!
6318  * \brief Finds concurrent sub-meshes
6319  */
6320 //=============================================================================
6321
6322 TListOfListOfInt SMESH_Mesh_i::findConcurrentSubMeshes()
6323 {
6324   TListOfListOfInt anOrder;
6325   ::SMESH_Mesh& mesh = GetImpl();
6326   {
6327     // collect submeshes and detect concurrent algorithms and hypothesises
6328     TDimHypList dimHypListArr[4]; // dimHyp list for each shape dimension
6329
6330     map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
6331     for ( ; i_sm != _mapSubMesh.end(); i_sm++ ) {
6332       ::SMESH_subMesh* sm = (*i_sm).second;
6333       // shape of submesh
6334       const TopoDS_Shape& aSubMeshShape = sm->GetSubShape();
6335
6336       // list of assigned hypothesises
6337       const list <const SMESHDS_Hypothesis*>& hypList = mesh.GetHypothesisList(aSubMeshShape);
6338       // Find out dimensions where the submesh can be concurrent.
6339       // We define the dimensions by algo of each of hypotheses in hypList
6340       list <const SMESHDS_Hypothesis*>::const_iterator hypIt = hypList.begin();
6341       for( ; hypIt != hypList.end(); hypIt++ ) {
6342         SMESH_Algo* anAlgo = 0;
6343         const SMESH_Hypothesis* hyp = dynamic_cast<const SMESH_Hypothesis*>(*hypIt);
6344         if ( hyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO )
6345           // hyp it-self is algo
6346           anAlgo = (SMESH_Algo*)dynamic_cast<const SMESH_Algo*>(hyp);
6347         else {
6348           // try to find algorithm with help of sub-shapes
6349           TopExp_Explorer anExp( aSubMeshShape, shapeTypeByDim(hyp->GetDim()) );
6350           for ( ; !anAlgo && anExp.More(); anExp.Next() )
6351             anAlgo = mesh.GetGen()->GetAlgo( mesh, anExp.Current() );
6352         }
6353         if (!anAlgo)
6354           continue; // no algorithm assigned to a current submesh
6355
6356         int dim = anAlgo->GetDim(); // top concurrent dimension (see comment to SMESH_DimHyp)
6357         // the submesh can concurrent at <dim> (or lower dims if !anAlgo->NeedDiscreteBoundary())
6358
6359         // create instance of dimension-hypothesis for found concurrent dimension(s) and algorithm
6360         for ( int j = anAlgo->NeedDiscreteBoundary() ? dim : 1, jn = dim; j <= jn; j++ )
6361           addDimHypInstance( j, aSubMeshShape, anAlgo, sm, hypList, dimHypListArr );
6362       }
6363     } // end iterations on submesh
6364
6365     // iterate on created dimension-hypotheses and check for concurrents
6366     for ( int i = 0; i < 4; i++ ) {
6367       const TDimHypList& listOfDimHyp = dimHypListArr[i];
6368       // check for concurrents in own and other dimensions (step-by-step)
6369       TDimHypList::const_iterator dhIt = listOfDimHyp.begin();
6370       for ( ; dhIt != listOfDimHyp.end(); dhIt++ ) {
6371         const SMESH_DimHyp* dimHyp = *dhIt;
6372         TDimHypList listOfConcurr;
6373         set<int>    setOfConcurrIds;
6374         // looking for concurrents and collect into own list
6375         for ( int j = i; j < 4; j++ )
6376           findConcurrents( dimHyp, dimHypListArr[j], listOfConcurr, setOfConcurrIds );
6377         // check if any concurrents found
6378         if ( listOfConcurr.size() > 0 ) {
6379           // add own submesh to list of concurrent
6380           addInOrderOfPriority( dimHyp, listOfConcurr );
6381           list<int> listOfConcurrIds;
6382           TDimHypList::iterator hypIt = listOfConcurr.begin();
6383           for ( ; hypIt != listOfConcurr.end(); ++hypIt )
6384             listOfConcurrIds.push_back( (*hypIt)->_subMesh->GetId() );
6385           anOrder.push_back( listOfConcurrIds );
6386         }
6387       }
6388     }
6389
6390     removeDimHyps(dimHypListArr);
6391
6392     // now, minimize the number of concurrent groups
6393     // Here we assume that lists of submeshes can have same submesh
6394     // in case of multi-dimension algorithms, as result
6395     //  list with common submesh has to be united into one list
6396     int listIndx = 0;
6397     TListOfListOfInt::iterator listIt = anOrder.begin();
6398     for(; listIt != anOrder.end(); listIt++, listIndx++ )
6399       unionLists( *listIt,  anOrder, listIndx + 1 );
6400   }
6401
6402   return anOrder;
6403 }
6404
6405 //=============================================================================
6406 /*!
6407  * \brief Set submesh object order
6408  * \param theSubMeshArray submesh array order
6409  */
6410 //=============================================================================
6411
6412 ::CORBA::Boolean SMESH_Mesh_i::SetMeshOrder(const SMESH::submesh_array_array& theSubMeshArray)
6413 {
6414   if ( _preMeshInfo )
6415     _preMeshInfo->ForgetOrLoad();
6416
6417   bool res = false;
6418   ::SMESH_Mesh& mesh = GetImpl();
6419
6420   TPythonDump aPythonDump; // prevent dump of called methods
6421   aPythonDump << "isDone = " << SMESH::SMESH_Mesh_var(_this()) << ".SetMeshOrder( [ ";
6422
6423   TListOfListOfInt subMeshOrder;
6424   for ( int i = 0, n = theSubMeshArray.length(); i < n; i++ )
6425   {
6426     const SMESH::submesh_array& aSMArray = theSubMeshArray[i];
6427     TListOfInt subMeshIds;
6428     if ( i > 0 )
6429       aPythonDump << ", ";
6430     aPythonDump << "[ ";
6431     // Collect subMeshes which should be clear
6432     //  do it list-by-list, because modification of submesh order
6433     //  take effect between concurrent submeshes only
6434     set<const SMESH_subMesh*> subMeshToClear;
6435     list<const SMESH_subMesh*> subMeshList;
6436     for ( int j = 0, jn = aSMArray.length(); j < jn; j++ )
6437     {
6438       const SMESH::SMESH_subMesh_var subMesh = SMESH::SMESH_subMesh::_duplicate(aSMArray[j]);
6439       if ( j > 0 )
6440         aPythonDump << ", ";
6441       aPythonDump << subMesh;
6442       subMeshIds.push_back( subMesh->GetId() );
6443       // detect common parts of submeshes
6444       if ( _mapSubMesh.find(subMesh->GetId()) != _mapSubMesh.end() )
6445         findCommonSubMesh( subMeshList, _mapSubMesh[ subMesh->GetId() ], subMeshToClear );
6446     }
6447     aPythonDump << " ]";
6448     subMeshOrder.push_back( subMeshIds );
6449
6450     // clear collected sub-meshes
6451     set<const SMESH_subMesh*>::iterator clrIt = subMeshToClear.begin();
6452     for ( ; clrIt != subMeshToClear.end(); clrIt++ )
6453       if ( SMESH_subMesh* sm = (SMESH_subMesh*)*clrIt )
6454       {
6455         sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
6456         if ( SMESH_Algo* algo = sm->GetAlgo() ) // #16748
6457           sm->AlgoStateEngine( SMESH_subMesh::MODIF_HYP, algo ); // to clear a cached algo
6458       }
6459   }
6460   aPythonDump << " ])";
6461
6462   mesh.SetMeshOrder( subMeshOrder );
6463   res = true;
6464
6465   SMESH::SMESH_Mesh_var me = _this();
6466   _gen_i->UpdateIcons( me );
6467
6468   return res;
6469 }
6470
6471 //=============================================================================
6472 /*!
6473  * \brief Convert submesh ids into submesh interfaces
6474  */
6475 //=============================================================================
6476
6477 void SMESH_Mesh_i::convertMeshOrder (const TListOfListOfInt&     theIdsOrder,
6478                                      SMESH::submesh_array_array& theResOrder,
6479                                      const bool                  theIsDump)
6480 {
6481   int nbSet = theIdsOrder.size();
6482   TPythonDump aPythonDump; // prevent dump of called methods
6483   if ( theIsDump )
6484     aPythonDump << "[ ";
6485   theResOrder.length(nbSet);
6486   TListOfListOfInt::const_iterator it = theIdsOrder.begin();
6487   int listIndx = 0;
6488   for( ; it != theIdsOrder.end(); it++ ) {
6489     // translate submesh identificators into submesh objects
6490     //  takeing into account real number of concurrent lists
6491     const TListOfInt& aSubOrder = (*it);
6492     if (!aSubOrder.size())
6493       continue;
6494     if ( theIsDump )
6495       aPythonDump << "[ ";
6496     // convert shape indices into interfaces
6497     SMESH::submesh_array_var aResSubSet = new SMESH::submesh_array();
6498     aResSubSet->length(aSubOrder.size());
6499     TListOfInt::const_iterator subIt = aSubOrder.begin();
6500     int j;
6501     for( j = 0; subIt != aSubOrder.end(); subIt++ ) {
6502       if ( _mapSubMeshIor.find(*subIt) == _mapSubMeshIor.end() )
6503         continue;
6504       SMESH::SMESH_subMesh_var subMesh =
6505         SMESH::SMESH_subMesh::_duplicate( _mapSubMeshIor[*subIt] );
6506       if ( theIsDump ) {
6507         if ( j > 0 )
6508           aPythonDump << ", ";
6509         aPythonDump << subMesh;
6510       }
6511       aResSubSet[ j++ ] = subMesh;
6512     }
6513     if ( theIsDump )
6514       aPythonDump << " ]";
6515     if ( j > 1 )
6516       theResOrder[ listIndx++ ] = aResSubSet;
6517   }
6518   // correct number of lists
6519   theResOrder.length( listIndx );
6520
6521   if ( theIsDump ) {
6522     // finilise python dump
6523     aPythonDump << " ]";
6524     aPythonDump << " = " << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshOrder()";
6525   }
6526 }
6527
6528 namespace // utils used by SMESH_MeshPartDS
6529 {
6530   /*!
6531    * \brief Class used to access to protected data of SMDS_MeshInfo
6532    */
6533   struct TMeshInfo : public SMDS_MeshInfo
6534   {
6535     void Add(const SMDS_MeshElement* e) { SMDS_MeshInfo::addWithPoly( e ); }
6536   };
6537   /*!
6538    * \brief Element holing its ID only
6539    */
6540   struct TElemID : public SMDS_LinearEdge
6541   {
6542     TElemID(int ID) : SMDS_LinearEdge(0,0) { setID( ID ); }
6543   };
6544 }
6545
6546 //================================================================================
6547 //
6548 // Implementation of SMESH_MeshPartDS
6549 //
6550 SMESH_MeshPartDS::SMESH_MeshPartDS(SMESH::SMESH_IDSource_ptr meshPart):
6551   SMESHDS_Mesh( /*meshID=*/-1, /*isEmbeddedMode=*/true)
6552 {
6553   SMESH::SMESH_Mesh_var mesh = meshPart->GetMesh();
6554   SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
6555
6556   mesh_i->Load();
6557   _meshDS = mesh_i->GetImpl().GetMeshDS();
6558
6559   SetPersistentId( _meshDS->GetPersistentId() );
6560
6561   if ( mesh_i == SMESH::DownCast<SMESH_Mesh_i*>( meshPart ))
6562   {
6563     // <meshPart> is the whole mesh
6564     myInfo = _meshDS->GetMeshInfo(); // copy mesh info;
6565     // copy groups
6566     set<SMESHDS_GroupBase*>& myGroupSet = const_cast<set<SMESHDS_GroupBase*>&>( GetGroups() );
6567     myGroupSet = _meshDS->GetGroups();
6568   }
6569   else
6570   {
6571     TMeshInfo tmpInfo;
6572     SMESH::long_array_var           anIDs = meshPart->GetIDs();
6573     SMESH::array_of_ElementType_var types = meshPart->GetTypes();
6574     if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
6575     {
6576       for ( CORBA::ULong i=0; i < anIDs->length(); i++ )
6577         if ( const SMDS_MeshNode * n = _meshDS->FindNode( anIDs[i] ))
6578           if ( _elements[ SMDSAbs_Node ].insert( n ).second )
6579             tmpInfo.Add( n );
6580     }
6581     else
6582     {
6583       for ( CORBA::ULong i=0; i < anIDs->length(); i++ )
6584         if ( const SMDS_MeshElement * e = _meshDS->FindElement(anIDs[i]))
6585           if ( _elements[ e->GetType() ].insert( e ).second )
6586           {
6587             tmpInfo.Add( e );
6588             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
6589             while ( nIt->more() )
6590             {
6591               const SMDS_MeshNode * n = (const SMDS_MeshNode*) nIt->next();
6592               if ( _elements[ SMDSAbs_Node ].insert( n ).second )
6593                 tmpInfo.Add( n );
6594             }
6595           }
6596     }
6597     myInfo = tmpInfo;
6598
6599     ShapeToMesh( _meshDS->ShapeToMesh() );
6600
6601     _meshDS = 0; // to enforce iteration on _elements and _nodes
6602   }
6603 }
6604 // -------------------------------------------------------------------------------------
6605 SMESH_MeshPartDS::SMESH_MeshPartDS(const std::list< const SMDS_MeshElement* > & meshPart):
6606   SMESHDS_Mesh( /*meshID=*/-1, /*isEmbeddedMode=*/true), _meshDS(0)
6607 {
6608   TMeshInfo tmpInfo;
6609   list< const SMDS_MeshElement* >::const_iterator partIt = meshPart.begin();
6610   for ( ; partIt != meshPart.end(); ++partIt )
6611     if ( const SMDS_MeshElement * e = *partIt )
6612       if ( _elements[ e->GetType() ].insert( e ).second )
6613       {
6614         tmpInfo.Add( e );
6615         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
6616         while ( nIt->more() )
6617         {
6618           const SMDS_MeshNode * n = (const SMDS_MeshNode*) nIt->next();
6619           if ( _elements[ SMDSAbs_Node ].insert( n ).second )
6620             tmpInfo.Add( n );
6621         }
6622       }
6623   myInfo = tmpInfo;
6624 }
6625 // -------------------------------------------------------------------------------------
6626 const SMDS_MeshElement * SMESH_MeshPartDS::FindElement(int IDelem) const
6627 {
6628   if ( _meshDS ) return _meshDS->FindElement( IDelem );
6629
6630   TElemID elem( IDelem );
6631   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
6632     if ( !_elements[ iType ].empty() )
6633     {
6634       TIDSortedElemSet::const_iterator it = _elements[ iType ].find( &elem );
6635       if ( it != _elements[ iType ].end() )
6636         return *it;
6637     }
6638   return 0;
6639 }
6640 // -------------------------------------------------------------------------------------
6641 bool SMESH_MeshPartDS::HasNumerationHoles()
6642 {
6643   if ( _meshDS ) return _meshDS->HasNumerationHoles();
6644
6645   return ( MinNodeID() != 1 ||
6646            MaxNodeID() != NbNodes() ||
6647            MinElementID() != 1 ||
6648            MaxElementID() != NbElements() );
6649 }
6650 // -------------------------------------------------------------------------------------
6651 int SMESH_MeshPartDS::MaxNodeID() const
6652 {
6653   if ( _meshDS ) return _meshDS->MaxNodeID();
6654   return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].rbegin())->GetID();
6655 }
6656 // -------------------------------------------------------------------------------------
6657 int SMESH_MeshPartDS::MinNodeID() const
6658 {
6659   if ( _meshDS ) return _meshDS->MinNodeID();
6660   return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].begin())->GetID();
6661 }  
6662 // -------------------------------------------------------------------------------------
6663 int SMESH_MeshPartDS::MaxElementID() const
6664 {
6665   if ( _meshDS ) return _meshDS->MaxElementID();
6666   int maxID = 0;
6667   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
6668     if ( !_elements[ iType ].empty() )
6669       maxID = Max( maxID, (*_elements[ iType ].rbegin())->GetID() );
6670   return maxID;
6671 }
6672 // -------------------------------------------------------------------------------------
6673 int SMESH_MeshPartDS::MinElementID() const
6674 {
6675   if ( _meshDS ) return _meshDS->MinElementID();
6676   int minID = 0;
6677   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
6678     if ( !_elements[ iType ].empty() )
6679       minID = Min( minID, (*_elements[ iType ].begin())->GetID() );
6680   return minID;
6681 }
6682 // -------------------------------------------------------------------------------------
6683 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementGeomIterator(SMDSAbs_GeometryType geomType) const
6684 {
6685   if ( _meshDS ) return _meshDS->elementGeomIterator( geomType );
6686
6687   typedef SMDS_SetIterator
6688     <const SMDS_MeshElement*,
6689     TIDSortedElemSet::const_iterator,
6690     SMDS::SimpleAccessor<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator>,
6691     SMDS_MeshElement::GeomFilter
6692     > TIter;
6693
6694   SMDSAbs_ElementType type = SMDS_MeshCell::ElemType( geomType );
6695
6696   return SMDS_ElemIteratorPtr( new TIter( _elements[type].begin(),
6697                                           _elements[type].end(),
6698                                           SMDS_MeshElement::GeomFilter( geomType )));
6699 }
6700 // -------------------------------------------------------------------------------------
6701 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementEntityIterator(SMDSAbs_EntityType entity) const
6702 {
6703   if ( _meshDS ) return _meshDS->elementEntityIterator( entity );
6704
6705   typedef SMDS_SetIterator
6706     <const SMDS_MeshElement*,
6707     TIDSortedElemSet::const_iterator,
6708     SMDS::SimpleAccessor<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator>,
6709     SMDS_MeshElement::EntityFilter
6710     > TIter;
6711
6712   SMDSAbs_ElementType type = SMDS_MeshCell::ElemType( entity );
6713
6714   return SMDS_ElemIteratorPtr( new TIter( _elements[type].begin(),
6715                                           _elements[type].end(),
6716                                           SMDS_MeshElement::EntityFilter( entity )));
6717 }
6718 // -------------------------------------------------------------------------------------
6719 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementsIterator(SMDSAbs_ElementType type) const
6720 {
6721   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
6722   if ( type == SMDSAbs_All && !_meshDS )
6723   {
6724     typedef vector< SMDS_ElemIteratorPtr > TIterVec;
6725     TIterVec iterVec;
6726     for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
6727       if ( !_elements[i].empty() && i != SMDSAbs_Node )
6728         iterVec.push_back
6729           ( SMDS_ElemIteratorPtr( new TIter( _elements[i].begin(), _elements[i].end() )));
6730
6731     typedef SMDS_IteratorOnIterators<const SMDS_MeshElement*, TIterVec > TIterOnIters;
6732     return SMDS_ElemIteratorPtr( new TIterOnIters( iterVec ));
6733   }
6734   return _meshDS ? _meshDS->elementsIterator(type) : SMDS_ElemIteratorPtr
6735       ( new TIter( _elements[type].begin(), _elements[type].end() ));
6736 }
6737 // -------------------------------------------------------------------------------------
6738 #define _GET_ITER_DEFINE( iterType, methName, elem, elemType)                       \
6739   iterType SMESH_MeshPartDS::methName() const                 \
6740   {                                                                                 \
6741     typedef SMDS_SetIterator<const elem*, TIDSortedElemSet::const_iterator > TIter; \
6742     return _meshDS ? _meshDS->methName() : iterType                 \
6743       ( new TIter( _elements[elemType].begin(), _elements[elemType].end() ));       \
6744   }
6745 // -------------------------------------------------------------------------------------
6746 _GET_ITER_DEFINE( SMDS_NodeIteratorPtr, nodesIterator, SMDS_MeshNode, SMDSAbs_Node )
6747 _GET_ITER_DEFINE( SMDS_EdgeIteratorPtr, edgesIterator, SMDS_MeshEdge, SMDSAbs_Edge )
6748 _GET_ITER_DEFINE( SMDS_FaceIteratorPtr, facesIterator, SMDS_MeshFace, SMDSAbs_Face )
6749 _GET_ITER_DEFINE( SMDS_VolumeIteratorPtr, volumesIterator, SMDS_MeshVolume, SMDSAbs_Volume)
6750 #undef _GET_ITER_DEFINE
6751 //
6752 // END Implementation of SMESH_MeshPartDS
6753 //
6754 //================================================================================