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