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