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