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