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